Fix Ghostty terminal spawn issues with dynamic delays (#408)

* Fix Ghostty terminal spawn issues with dynamic delays

- Add isTerminalRunning() helper to check if terminal app is running
- Implement dynamic delays for Ghostty based on running state
  - 0.5s delay for warm start (already running)
  - 2.0s delay for cold start (needs to launch)
- Add window count checking to ensure UI is ready
- Fix issue where commands weren't executed when Ghostty had no windows

Fixes #371

* Fix CI: Skip Node.js check when using pre-built web artifacts

- Add SKIP_NODE_CHECK=true environment variable to Mac CI build step
- Prevents install-node.sh from failing when pnpm is not available
- CI downloads pre-built web artifacts, so Node.js/pnpm are not needed

* Fix CI: Properly handle pre-built web artifacts in Mac build

- Add early exit in build-web-frontend.sh when CI has pre-built artifacts
- Set CI=true environment variable in all Xcode build steps
- Update node-path-setup.sh to skip Node.js check in CI
- Copy pre-built artifacts directly without attempting rebuild
- This prevents pnpm dependency errors in CI environment

* Fix SwiftFormat modifier order issue

- Change 'static weak' to 'weak static' in AppDelegate
- SwiftFormat requires consistent modifier ordering

* Fix CI: Include native binaries in web artifacts

- Add web/native/ directory to uploaded artifacts
- Add web/bin/vt script to uploaded artifacts
- This ensures Mac tests can find the vibetunnel executable
- Fixes test failures due to missing server binary

* Fix CI: Copy native binaries from web artifacts in Mac CI

- Update artifact extraction to copy web/native/ directory
- Also copy web/bin/ directory for vt script
- Add debugging output to show native contents
- This ensures tests can find the vibetunnel executable
This commit is contained in:
Peter Steinberger 2025-07-18 17:24:30 +02:00 committed by GitHub
parent 3311f34867
commit bc9f505026
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 133 additions and 7 deletions

View file

@ -128,10 +128,10 @@ jobs:
find web-artifacts-temp -type f | head -20 || echo "No files found"
# Ensure web directory structure exists
mkdir -p web/dist web/public/bundle
mkdir -p web/dist web/public/bundle web/native web/bin
# The artifacts are uploaded without the web/ prefix
# So they're at web-artifacts-temp/dist and web-artifacts-temp/public/bundle
# So they're at web-artifacts-temp/dist, web-artifacts-temp/public/bundle, etc.
if [ -d "web-artifacts-temp/dist" ]; then
# Copy from the root of artifacts
cp -r web-artifacts-temp/dist/* web/dist/ 2>/dev/null || true
@ -141,6 +141,14 @@ jobs:
cp -r web-artifacts-temp/public/bundle/* web/public/bundle/ 2>/dev/null || true
echo "Copied bundle files"
fi
if [ -d "web-artifacts-temp/native" ]; then
cp -r web-artifacts-temp/native/* web/native/ 2>/dev/null || true
echo "Copied native binaries"
fi
if [ -d "web-artifacts-temp/bin" ]; then
cp -r web-artifacts-temp/bin/* web/bin/ 2>/dev/null || true
echo "Copied bin scripts"
fi
# Debug: Show what we have
echo "=== Web directory structure ==="
@ -149,6 +157,8 @@ jobs:
ls -la web/dist/ | head -10 || true
echo "=== Bundle contents ==="
ls -la web/public/bundle/ | head -10 || true
echo "=== Native contents ==="
ls -la web/native/ | head -10 || true
# Clean up temp directory
rm -rf web-artifacts-temp
@ -162,6 +172,9 @@ jobs:
echo "Web artifacts successfully downloaded and positioned"
- name: Resolve Dependencies (once)
env:
CI: "true" # Ensure CI environment variable is set
SKIP_NODE_CHECK: "true" # Skip Node.js check in CI since we download pre-built artifacts
run: |
echo "Resolving Swift package dependencies..."
# Workspace is at root level
@ -175,6 +188,9 @@ jobs:
- name: Build Debug
timeout-minutes: 10
id: build
env:
CI: "true" # Ensure CI environment variable is set for build scripts
SKIP_NODE_CHECK: "true" # Skip Node.js check in CI since we download pre-built artifacts
run: |
# Always use Debug for now to match test expectations
BUILD_CONFIG="Debug"
@ -218,6 +234,8 @@ jobs:
- name: Run tests with coverage
id: test-coverage
timeout-minutes: 15
env:
SKIP_NODE_CHECK: "true" # Skip Node.js check in CI since we download pre-built artifacts
run: |
# Debug: Check if web build artifacts were downloaded
echo "=== Checking web build artifacts ==="

View file

@ -281,6 +281,8 @@ jobs:
path: |
web/dist/
web/public/bundle/
web/native/
web/bin/vt
retention-days: 1
if-no-files-found: error

View file

@ -55,7 +55,7 @@ struct CLIInstallationSection: View {
}
.buttonStyle(.bordered)
.disabled(cliInstaller.isInstalling)
Button(action: {
Task {
await cliInstaller.uninstall()
@ -88,7 +88,7 @@ struct CLIInstallationSection: View {
.foregroundColor(.accentColor)
.help("Reinstall CLI tool")
}
Button(action: {
Task {
await cliInstaller.uninstall()

View file

@ -369,7 +369,8 @@ final class CLIInstaller {
logger.debug("Could not read error output: \(error.localizedDescription)")
errorString = "Unknown error (could not read stderr)"
}
logger.error("CLIInstaller: Uninstallation failed with status \(task.terminationStatus): \(errorString)")
logger
.error("CLIInstaller: Uninstallation failed with status \(task.terminationStatus): \(errorString)")
lastError = "Uninstallation failed: \(errorString)"
isInstalling = false
isUninstalling = false

View file

@ -145,6 +145,12 @@ enum Terminal: String, CaseIterable {
allCases.filter(\.isInstalled)
}
/// Check if a specific terminal application is currently running
static func isTerminalRunning(_ terminal: Self) -> Bool {
let runningApps = NSWorkspace.shared.runningApplications
return runningApps.contains { $0.bundleIdentifier == terminal.bundleIdentifier }
}
/// Generate unified AppleScript for all terminals
func unifiedAppleScript(for config: TerminalLaunchConfig) -> String {
// Terminal.app supports 'do script' which handles complex commands better
@ -201,6 +207,40 @@ enum Terminal: String, CaseIterable {
"""
}
// Special handling for Ghostty with dynamic delays based on running state
if self == .ghostty {
let isRunning = Self.isTerminalRunning(.ghostty)
let startupDelay = isRunning ? "0.5" : "2.0" // Longer delay for cold start
return """
tell application "\(processName)"
activate
-- Wait longer if Ghostty wasn't already running
delay 0.2
set windowCount to 0
try
set windowCount to count of windows
end try
if windowCount = 0 then
-- No windows open, need extra time for UI initialization
delay \(startupDelay)
end if
tell application "System Events"
tell process "\(processName)"
-- Create new window
keystroke "n" using {command down}
delay 0.5
-- Paste command from clipboard
keystroke "v" using {command down}
delay 0.1
-- Execute the command
key code 36
end tell
end tell
end tell
"""
}
// For other terminals, Cmd+N typically creates a new window
return """
tell application "\(processName)"

View file

@ -26,6 +26,54 @@ fi
APP_RESOURCES="${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
# In CI with pre-built artifacts, skip the entire build process
if [ "${CI}" = "true" ] && [ -f "${WEB_DIR}/dist/server/server.js" ]; then
echo "✓ CI environment detected with pre-built web artifacts"
echo "✓ Skipping web frontend build entirely"
# Still need to copy the pre-built files to the app bundle
# Clean and create destination directory
echo "Cleaning destination directory..."
rm -rf "${DEST_DIR}"
mkdir -p "${DEST_DIR}"
# Copy built files to Resources
echo "Copying pre-built web files to app bundle..."
if [ -d "${PUBLIC_DIR}" ]; then
cp -R "${PUBLIC_DIR}/"* "${DEST_DIR}/"
fi
# Copy native executable and modules to app bundle if they exist
NATIVE_DIR="${WEB_DIR}/native"
if [ -f "${NATIVE_DIR}/vibetunnel" ]; then
echo "Copying native executable to app bundle..."
cp "${NATIVE_DIR}/vibetunnel" "${APP_RESOURCES}/"
chmod +x "${APP_RESOURCES}/vibetunnel"
fi
if [ -f "${NATIVE_DIR}/pty.node" ]; then
cp "${NATIVE_DIR}/pty.node" "${APP_RESOURCES}/"
fi
if [ -f "${NATIVE_DIR}/spawn-helper" ]; then
cp "${NATIVE_DIR}/spawn-helper" "${APP_RESOURCES}/"
chmod +x "${APP_RESOURCES}/spawn-helper"
fi
if [ -f "${NATIVE_DIR}/authenticate_pam.node" ]; then
cp "${NATIVE_DIR}/authenticate_pam.node" "${APP_RESOURCES}/"
fi
if [ -f "${WEB_DIR}/bin/vt" ]; then
cp "${WEB_DIR}/bin/vt" "${APP_RESOURCES}/"
chmod +x "${APP_RESOURCES}/vt"
fi
echo "✓ Pre-built web artifacts copied successfully"
exit 0
fi
# Read the current hash
if [ -f "${HASH_FILE}" ]; then
CURRENT_HASH=$(cat "${HASH_FILE}")
@ -71,7 +119,13 @@ source "${SCRIPT_DIR}/node-path-setup.sh"
# Export CI to prevent interactive prompts
export CI=true
# Check if pnpm is available
# Check if pnpm is available (skip in CI when web artifacts are pre-built)
if [ "${SKIP_NODE_CHECK}" = "true" ] && [ "${CI}" = "true" ]; then
echo "✓ Skipping pnpm check in CI (web artifacts are pre-built)"
echo "✓ This script should not be running in CI - web build should already be complete"
exit 0
fi
if ! command -v pnpm &> /dev/null; then
echo "error: pnpm not found. Please install pnpm"
exit 1

View file

@ -16,6 +16,12 @@ fi
echo "Checking for Node.js..."
# Skip Node.js check in CI when web artifacts are pre-built
if [ "${CI}" = "true" ] && [ "${SKIP_NODE_CHECK}" = "true" ]; then
echo "✓ Skipping Node.js check in CI (web artifacts are pre-built)"
exit 0
fi
# Load Node.js environment managers (Homebrew, nvm, Volta, fnm)
source "${SCRIPT_DIR}/node-path-setup.sh"

View file

@ -22,7 +22,12 @@ else
export PATH="/opt/homebrew/bin:/usr/local/bin:$HOME/.volta/bin:$HOME/Library/pnpm:$HOME/.bun/bin:$PATH"
fi
# Verify Node.js is available
# Verify Node.js is available (skip in CI when using pre-built artifacts)
if [ "${SKIP_NODE_CHECK}" = "true" ] && [ "${CI}" = "true" ]; then
# In CI with pre-built artifacts, Node.js is not required
return 0 2>/dev/null || exit 0
fi
if ! command -v node >/dev/null 2>&1; then
echo "error: Node.js not found. Install via: brew install node" >&2
return 1 2>/dev/null || exit 1