From a3b3849188235746a4fcd57a4adabdb8ca61b296 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Tue, 11 Nov 2025 23:47:59 +0100 Subject: [PATCH] Fix SelectList crash on narrow terminal and thinking level restoration SelectList fixes: - Use hardcoded visual width for arrow prefix instead of string length which includes ANSI codes - Truncate scroll indicator text to prevent exceeding terminal width - Fixes crash when terminal is resized narrow and arrow keys are pressed Thinking level fix: - Restore thinking level even if it's "off" (removed !== "off" check) - This ensures the thinking level selector shows the correct state on continue --- packages/coding-agent/long-data.json | 263 +++++++++++++++++++++ packages/coding-agent/src/main.ts | 2 +- packages/tui/src/components/select-list.ts | 15 +- 3 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 packages/coding-agent/long-data.json diff --git a/packages/coding-agent/long-data.json b/packages/coding-agent/long-data.json new file mode 100644 index 00000000..b7f8943a --- /dev/null +++ b/packages/coding-agent/long-data.json @@ -0,0 +1,263 @@ +{ + "project": { + "id": "proj_9876543210", + "name": "Advanced E-Commerce Platform", + "description": "A comprehensive multi-vendor marketplace with real-time analytics", + "status": "active", + "created": "2024-01-15T08:30:00Z", + "updated": "2024-03-20T14:45:00Z", + "version": "2.4.1" + }, + "team": { + "members": [ + { + "id": "usr_001", + "name": "Sarah Chen", + "role": "Lead Developer", + "email": "sarah.chen@example.com", + "skills": ["TypeScript", "React", "Node.js", "PostgreSQL"], + "joined": "2023-06-01", + "active": true + }, + { + "id": "usr_002", + "name": "Marcus Johnson", + "role": "Backend Engineer", + "email": "marcus.j@example.com", + "skills": ["Python", "Django", "Redis", "Docker"], + "joined": "2023-07-15", + "active": true + }, + { + "id": "usr_003", + "name": "Elena Rodriguez", + "role": "UX Designer", + "email": "elena.r@example.com", + "skills": ["Figma", "UI/UX", "Prototyping", "User Research"], + "joined": "2023-08-20", + "active": true + }, + { + "id": "usr_004", + "name": "Ahmed Hassan", + "role": "DevOps Engineer", + "email": "ahmed.h@example.com", + "skills": ["Kubernetes", "AWS", "Terraform", "CI/CD"], + "joined": "2023-09-10", + "active": true + } + ], + "departments": ["Engineering", "Design", "Operations", "Marketing"] + }, + "features": { + "authentication": { + "enabled": true, + "providers": ["email", "google", "github", "facebook"], + "mfa": true, + "sessionTimeout": 3600, + "passwordPolicy": { + "minLength": 12, + "requireUppercase": true, + "requireNumbers": true, + "requireSpecialChars": true + } + }, + "payments": { + "enabled": true, + "gateways": ["stripe", "paypal", "square"], + "currencies": ["USD", "EUR", "GBP", "JPY", "CAD", "AUD"], + "refunds": true, + "subscriptions": true + }, + "analytics": { + "enabled": true, + "realtime": true, + "metrics": ["pageViews", "conversions", "revenue", "userActivity"], + "reporting": { + "daily": true, + "weekly": true, + "monthly": true, + "custom": true + } + } + }, + "infrastructure": { + "cloud": { + "provider": "AWS", + "region": "us-east-1", + "zones": ["us-east-1a", "us-east-1b", "us-east-1c"], + "services": { + "compute": ["EC2", "Lambda", "ECS"], + "storage": ["S3", "EBS", "EFS"], + "database": ["RDS", "DynamoDB", "ElastiCache"], + "networking": ["VPC", "CloudFront", "Route53"] + } + }, + "monitoring": { + "tools": ["Prometheus", "Grafana", "DataDog", "Sentry"], + "alerts": { + "email": true, + "slack": true, + "pagerduty": true + } + } + }, + "api": { + "version": "v2", + "baseUrl": "https://api.example.com", + "endpoints": [ + { + "path": "/users", + "methods": ["GET", "POST", "PUT", "DELETE"], + "auth": true, + "rateLimit": 1000 + }, + { + "path": "/products", + "methods": ["GET", "POST", "PUT", "DELETE"], + "auth": true, + "rateLimit": 5000 + }, + { + "path": "/orders", + "methods": ["GET", "POST", "PUT"], + "auth": true, + "rateLimit": 2000 + }, + { + "path": "/analytics", + "methods": ["GET"], + "auth": true, + "rateLimit": 500 + } + ], + "documentation": "https://docs.example.com/api" + }, + "database": { + "primary": { + "type": "PostgreSQL", + "version": "15.2", + "host": "db-primary.example.com", + "port": 5432, + "replicas": 3, + "backup": { + "enabled": true, + "frequency": "hourly", + "retention": 30 + } + }, + "cache": { + "type": "Redis", + "version": "7.0", + "host": "cache.example.com", + "port": 6379, + "ttl": 3600 + } + }, + "security": { + "ssl": { + "enabled": true, + "provider": "LetsEncrypt", + "autoRenew": true + }, + "firewall": { + "enabled": true, + "rules": [ + { + "name": "allow-https", + "port": 443, + "protocol": "TCP", + "source": "0.0.0.0/0" + }, + { + "name": "allow-http", + "port": 80, + "protocol": "TCP", + "source": "0.0.0.0/0" + }, + { + "name": "allow-ssh", + "port": 22, + "protocol": "TCP", + "source": "10.0.0.0/8" + } + ] + }, + "scanning": { + "vulnerabilities": true, + "dependencies": true, + "secrets": true + } + }, + "testing": { + "unit": { + "framework": "Vitest", + "coverage": 87.5, + "threshold": 80 + }, + "integration": { + "framework": "Playwright", + "browsers": ["chromium", "firefox", "webkit"], + "coverage": 72.3 + }, + "e2e": { + "framework": "Cypress", + "coverage": 65.8 + } + }, + "deployment": { + "strategy": "blue-green", + "automation": true, + "environments": [ + { + "name": "development", + "url": "https://dev.example.com", + "branch": "develop", + "autoDeployOn": ["push"] + }, + { + "name": "staging", + "url": "https://staging.example.com", + "branch": "staging", + "autoDeployOn": ["pull_request"] + }, + { + "name": "production", + "url": "https://example.com", + "branch": "main", + "autoDeployOn": ["tag"] + } + ] + }, + "logs": { + "level": "info", + "format": "json", + "retention": 90, + "aggregation": { + "enabled": true, + "service": "CloudWatch", + "queries": [ + "error count by hour", + "request latency p95", + "unique users per day" + ] + } + }, + "compliance": { + "gdpr": true, + "ccpa": true, + "hipaa": false, + "soc2": true, + "dataRetention": { + "user": 2555, + "logs": 90, + "backups": 30 + } + }, + "metadata": { + "tags": ["production", "ecommerce", "marketplace", "saas"], + "owner": "engineering-team", + "costCenter": "CC-2024-001", + "criticality": "high" + } +} diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index ce4875e8..f9a30ad0 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -230,7 +230,7 @@ export async function main(args: string[]) { // Load and restore thinking level const thinkingLevel = sessionManager.loadThinkingLevel() as ThinkingLevel; - if (thinkingLevel && thinkingLevel !== "off") { + if (thinkingLevel) { agent.setThinkingLevel(thinkingLevel); console.log(chalk.dim(`Restored thinking level: ${thinkingLevel}`)); } diff --git a/packages/tui/src/components/select-list.ts b/packages/tui/src/components/select-list.ts index d4f05402..12950d44 100644 --- a/packages/tui/src/components/select-list.ts +++ b/packages/tui/src/components/select-list.ts @@ -61,6 +61,7 @@ export class SelectList implements Component { if (isSelected) { // Use arrow indicator for selection const prefix = chalk.blue("→ "); + const prefixWidth = 2; // "→ " is 2 characters visually const displayValue = item.label || item.value; if (item.description && width > 40) { @@ -69,8 +70,8 @@ export class SelectList implements Component { const truncatedValue = displayValue.substring(0, maxValueLength); const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length)); - // Calculate remaining space for description - const descriptionStart = prefix.length + truncatedValue.length + spacing.length - 2; // -2 for arrow color codes + // Calculate remaining space for description using visible widths + const descriptionStart = prefixWidth + truncatedValue.length + spacing.length; const remainingWidth = width - descriptionStart - 2; // -2 for safety if (remainingWidth > 10) { @@ -78,12 +79,12 @@ export class SelectList implements Component { line = prefix + chalk.blue(truncatedValue) + chalk.gray(spacing + truncatedDesc); } else { // Not enough space for description - const maxWidth = width - 4; // 2 for arrow + space, 2 for safety + const maxWidth = width - prefixWidth - 2; line = prefix + chalk.blue(displayValue.substring(0, maxWidth)); } } else { // No description or not enough width - const maxWidth = width - 4; // 2 for arrow + space, 2 for safety + const maxWidth = width - prefixWidth - 2; line = prefix + chalk.blue(displayValue.substring(0, maxWidth)); } } else { @@ -120,7 +121,11 @@ export class SelectList implements Component { // Add scroll indicators if needed if (startIndex > 0 || endIndex < this.filteredItems.length) { - const scrollInfo = chalk.gray(` (${this.selectedIndex + 1}/${this.filteredItems.length})`); + const scrollText = ` (${this.selectedIndex + 1}/${this.filteredItems.length})`; + // Truncate if too long for terminal + const maxWidth = width - 2; + const truncated = scrollText.substring(0, maxWidth); + const scrollInfo = chalk.gray(truncated); lines.push(scrollInfo); }