diff --git a/.gitignore b/.gitignore index d77398636..871c98964 100644 --- a/.gitignore +++ b/.gitignore @@ -96,4 +96,4 @@ data/credentials.json data/ .codex/ .mcp.json -.planning \ No newline at end of file +.planning diff --git a/Dockerfile b/Dockerfile index 03911b45e..a68901e4d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -118,6 +118,7 @@ RUN curl -fsSL https://opencode.ai/install | bash && \ echo "=== Checking OpenCode CLI installation ===" && \ ls -la /home/automaker/.local/bin/ && \ (which opencode && opencode --version) || echo "opencode installed (may need auth setup)" + USER root # Add PATH to profile so it's available in all interactive shells (for login shells) @@ -147,6 +148,15 @@ COPY --from=server-builder /app/apps/server/package*.json ./apps/server/ # Copy node_modules (includes symlinks to libs) COPY --from=server-builder /app/node_modules ./node_modules +# Install Playwright Chromium browser for AI agent verification tests +# This adds ~300MB to the image but enables automated testing mode out of the box +# Using the locally installed playwright ensures we use the pinned version from package-lock.json +USER automaker +RUN ./node_modules/.bin/playwright install chromium && \ + echo "=== Playwright Chromium installed ===" && \ + ls -la /home/automaker/.cache/ms-playwright/ +USER root + # Create data and projects directories RUN mkdir -p /data /projects && chown automaker:automaker /data /projects diff --git a/README.md b/README.md index 49b143436..98f8683e2 100644 --- a/README.md +++ b/README.md @@ -367,6 +367,42 @@ services: The Docker image supports both AMD64 and ARM64 architectures. The GitHub CLI and Claude CLI are automatically downloaded for the correct architecture during build. +##### Playwright for Automated Testing + +The Docker image includes **Playwright Chromium pre-installed** for AI agent verification tests. When agents implement features in automated testing mode, they use Playwright to verify the implementation works correctly. + +**No additional setup required** - Playwright verification works out of the box. + +#### Optional: Persist browsers for manual updates + +By default, Playwright Chromium is pre-installed in the Docker image. If you need to manually update browsers or want to persist browser installations across container restarts (not image rebuilds), you can mount a volume. + +**Important:** When you first add this volume mount to an existing setup, the empty volume will override the pre-installed browsers. You must re-install them: + +```bash +# After adding the volume mount for the first time +docker exec --user automaker -w /app automaker-server npx playwright install chromium +``` + +Add this to your `docker-compose.override.yml`: + +```yaml +services: + server: + volumes: + - playwright-cache:/home/automaker/.cache/ms-playwright + +volumes: + playwright-cache: + name: automaker-playwright-cache +``` + +**Updating browsers manually:** + +```bash +docker exec --user automaker -w /app automaker-server npx playwright install chromium +``` + ### Testing #### End-to-End Tests (Playwright) diff --git a/apps/server/package.json b/apps/server/package.json index ed005c54b..4a7a75a8b 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -45,6 +45,7 @@ "yaml": "2.7.0" }, "devDependencies": { + "@playwright/test": "1.57.0", "@types/cookie": "0.6.0", "@types/cookie-parser": "1.4.10", "@types/cors": "2.8.19", diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 4f49d1172..85ff01458 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -211,7 +211,13 @@ const BOX_CONTENT_WIDTH = 67; pathsCheckedInfo = ` ║ ║ ║ ${'Paths checked:'.padEnd(BOX_CONTENT_WIDTH)}║ -${pathsChecked.map((p) => `║ ${p.substring(0, BOX_CONTENT_WIDTH - 4).padEnd(BOX_CONTENT_WIDTH - 4)} ║`).join('\n')}`; +${pathsChecked + .map((p) => { + const maxLen = BOX_CONTENT_WIDTH - 4; + const display = p.length > maxLen ? '...' + p.slice(-(maxLen - 3)) : p; + return `║ ${display.padEnd(maxLen)} ║`; + }) + .join('\n')}`; } } diff --git a/apps/server/src/routes/setup/routes/verify-claude-auth.ts b/apps/server/src/routes/setup/routes/verify-claude-auth.ts index 405ef9a64..7df27c3dc 100644 --- a/apps/server/src/routes/setup/routes/verify-claude-auth.ts +++ b/apps/server/src/routes/setup/routes/verify-claude-auth.ts @@ -322,11 +322,12 @@ export function createVerifyClaudeAuthHandler() { }); // Determine specific auth type for success messages + const effectiveAuthMethod = authMethod ?? 'api_key'; let authType: 'oauth' | 'api_key' | 'cli' | undefined; if (authenticated) { - if (authMethod === 'api_key') { + if (effectiveAuthMethod === 'api_key') { authType = 'api_key'; - } else if (authMethod === 'cli') { + } else if (effectiveAuthMethod === 'cli') { // Check if CLI auth is via OAuth (Claude Code subscription) or generic CLI try { const indicators = await getClaudeAuthIndicators(); diff --git a/apps/ui/src/components/views/board-view/shared/thinking-level-selector.tsx b/apps/ui/src/components/views/board-view/shared/thinking-level-selector.tsx index 5164e4fac..3a69d5879 100644 --- a/apps/ui/src/components/views/board-view/shared/thinking-level-selector.tsx +++ b/apps/ui/src/components/views/board-view/shared/thinking-level-selector.tsx @@ -9,7 +9,8 @@ interface ThinkingLevelSelectorProps { selectedLevel: ThinkingLevel; onLevelSelect: (level: ThinkingLevel) => void; testIdPrefix?: string; - /** Optional model ID to filter available thinking levels (e.g., Opus 4.6 only shows None/Adaptive) */ + /** Model ID is required for correct thinking level filtering. + * Without it, adaptive thinking won't be available for Opus 4.6. */ model?: string; } diff --git a/apps/ui/src/lib/agent-context-parser.ts b/apps/ui/src/lib/agent-context-parser.ts index 996b397b7..11c2a91ea 100644 --- a/apps/ui/src/lib/agent-context-parser.ts +++ b/apps/ui/src/lib/agent-context-parser.ts @@ -34,7 +34,7 @@ export const DEFAULT_MODEL = 'claude-opus-4-6'; */ export function formatModelName(model: string): string { // Claude models - if (model.includes('opus-4-6')) return 'Opus 4.6'; + if (model.includes('opus-4-6') || model === 'claude-opus') return 'Opus 4.6'; if (model.includes('opus')) return 'Opus 4.5'; if (model.includes('sonnet')) return 'Sonnet 4.5'; if (model.includes('haiku')) return 'Haiku 4.5'; diff --git a/docker-compose.override.yml.example b/docker-compose.override.yml.example index 3815c197d..e92ce119d 100644 --- a/docker-compose.override.yml.example +++ b/docker-compose.override.yml.example @@ -21,9 +21,13 @@ services: # - ~/.local/share/opencode:/home/automaker/.local/share/opencode # - ~/.config/opencode:/home/automaker/.config/opencode - # Playwright browser cache - persists installed browsers across container restarts - # Run 'npx playwright install --with-deps chromium' once, and it will persist + # ===== Playwright Browser Cache (Optional) ===== + # Playwright Chromium is PRE-INSTALLED in the Docker image for automated testing. + # Uncomment below to persist browser cache across container rebuilds (saves ~300MB download): # - playwright-cache:/home/automaker/.cache/ms-playwright + # + # To update Playwright browsers manually: + # docker exec --user automaker -w /app automaker-server npx playwright install chromium environment: # Set root directory for all projects and file operations # Users can only create/open projects within this directory @@ -37,6 +41,7 @@ services: # - CURSOR_API_KEY=${CURSOR_API_KEY:-} volumes: - # Playwright cache volume (persists Chromium installs) + # Playwright cache volume - optional, persists browser updates across container rebuilds + # Uncomment if you mounted the playwright-cache volume above # playwright-cache: # name: automaker-playwright-cache