Merge main into massive-terminal-upgrade

Resolves merge conflicts:
- apps/server/src/routes/terminal/common.ts: Keep randomBytes import, use @automaker/utils for createLogger
- apps/ui/eslint.config.mjs: Use main's explicit globals list with XMLHttpRequest and MediaQueryListEvent additions
- apps/ui/src/components/views/terminal-view.tsx: Keep our terminal improvements (killAllSessions, beforeunload, better error handling)
- apps/ui/src/config/terminal-themes.ts: Keep our search highlight colors for all themes
- apps/ui/src/store/app-store.ts: Keep our terminal settings persistence improvements (merge function)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
SuperComboGamer
2025-12-21 20:27:44 -05:00
393 changed files with 32473 additions and 17974 deletions

View File

@@ -1,6 +1,6 @@
import { Page } from "@playwright/test";
import { clickElement } from "../core/interactions";
import { waitForElement } from "../core/waiting";
import { Page } from '@playwright/test';
import { clickElement } from '../core/interactions';
import { waitForElement } from '../core/waiting';
/**
* Navigate to the board/kanban view
@@ -8,11 +8,11 @@ import { waitForElement } from "../core/waiting";
*/
export async function navigateToBoard(page: Page): Promise<void> {
// Navigate directly to /board route
await page.goto("/board");
await page.waitForLoadState("networkidle");
await page.goto('/board');
await page.waitForLoadState('networkidle');
// Wait for the board view to be visible
await waitForElement(page, "board-view", { timeout: 10000 });
await waitForElement(page, 'board-view', { timeout: 10000 });
}
/**
@@ -21,11 +21,11 @@ export async function navigateToBoard(page: Page): Promise<void> {
*/
export async function navigateToContext(page: Page): Promise<void> {
// Navigate directly to /context route
await page.goto("/context");
await page.waitForLoadState("networkidle");
await page.goto('/context');
await page.waitForLoadState('networkidle');
// Wait for the context view to be visible
await waitForElement(page, "context-view", { timeout: 10000 });
await waitForElement(page, 'context-view', { timeout: 10000 });
}
/**
@@ -34,11 +34,28 @@ export async function navigateToContext(page: Page): Promise<void> {
*/
export async function navigateToSpec(page: Page): Promise<void> {
// Navigate directly to /spec route
await page.goto("/spec");
await page.waitForLoadState("networkidle");
await page.goto('/spec');
await page.waitForLoadState('networkidle');
// Wait for the spec view to be visible
await waitForElement(page, "spec-view", { timeout: 10000 });
// Wait for loading state to complete first (if present)
const loadingElement = page.locator('[data-testid="spec-view-loading"]');
try {
const loadingVisible = await loadingElement.isVisible({ timeout: 2000 });
if (loadingVisible) {
// Wait for loading to disappear (spec view or empty state will appear)
await loadingElement.waitFor({ state: 'hidden', timeout: 10000 });
}
} catch {
// Loading element not found or already hidden, continue
}
// Wait for either the main spec view or empty state to be visible
// The spec-view element appears when loading is complete and spec exists
// The spec-view-empty element appears when loading is complete and spec doesn't exist
await Promise.race([
waitForElement(page, 'spec-view', { timeout: 10000 }).catch(() => null),
waitForElement(page, 'spec-view-empty', { timeout: 10000 }).catch(() => null),
]);
}
/**
@@ -47,11 +64,11 @@ export async function navigateToSpec(page: Page): Promise<void> {
*/
export async function navigateToAgent(page: Page): Promise<void> {
// Navigate directly to /agent route
await page.goto("/agent");
await page.waitForLoadState("networkidle");
await page.goto('/agent');
await page.waitForLoadState('networkidle');
// Wait for the agent view to be visible
await waitForElement(page, "agent-view", { timeout: 10000 });
await waitForElement(page, 'agent-view', { timeout: 10000 });
}
/**
@@ -60,11 +77,11 @@ export async function navigateToAgent(page: Page): Promise<void> {
*/
export async function navigateToSettings(page: Page): Promise<void> {
// Navigate directly to /settings route
await page.goto("/settings");
await page.waitForLoadState("networkidle");
await page.goto('/settings');
await page.waitForLoadState('networkidle');
// Wait for the settings view to be visible
await waitForElement(page, "settings-view", { timeout: 10000 });
await waitForElement(page, 'settings-view', { timeout: 10000 });
}
/**
@@ -73,31 +90,27 @@ export async function navigateToSettings(page: Page): Promise<void> {
*/
export async function navigateToSetup(page: Page): Promise<void> {
// Dynamic import to avoid circular dependency
const { setupFirstRun } = await import("../project/setup");
const { setupFirstRun } = await import('../project/setup');
await setupFirstRun(page);
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForElement(page, "setup-view", { timeout: 10000 });
await page.goto('/');
await page.waitForLoadState('networkidle');
await waitForElement(page, 'setup-view', { timeout: 10000 });
}
/**
* Navigate to the welcome view (clear project selection)
*/
export async function navigateToWelcome(page: Page): Promise<void> {
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForElement(page, "welcome-view", { timeout: 10000 });
await page.goto('/');
await page.waitForLoadState('networkidle');
await waitForElement(page, 'welcome-view', { timeout: 10000 });
}
/**
* Navigate to a specific view using the sidebar navigation
*/
export async function navigateToView(
page: Page,
viewId: string
): Promise<void> {
const navSelector =
viewId === "settings" ? "settings-button" : `nav-${viewId}`;
export async function navigateToView(page: Page, viewId: string): Promise<void> {
const navSelector = viewId === 'settings' ? 'settings-button' : `nav-${viewId}`;
await clickElement(page, navSelector);
await page.waitForTimeout(100);
}
@@ -108,7 +121,7 @@ export async function navigateToView(
export async function getCurrentView(page: Page): Promise<string | null> {
// Get the current view from zustand store via localStorage
const storage = await page.evaluate(() => {
const item = localStorage.getItem("automaker-storage");
const item = localStorage.getItem('automaker-storage');
return item ? JSON.parse(item) : null;
});