mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-25 09:25:50 +00:00
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:
parent
3311f34867
commit
bc9f505026
8 changed files with 133 additions and 7 deletions
22
.github/workflows/mac.yml
vendored
22
.github/workflows/mac.yml
vendored
|
|
@ -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 ==="
|
||||
|
|
|
|||
2
.github/workflows/node.yml
vendored
2
.github/workflows/node.yml
vendored
|
|
@ -281,6 +281,8 @@ jobs:
|
|||
path: |
|
||||
web/dist/
|
||||
web/public/bundle/
|
||||
web/native/
|
||||
web/bin/vt
|
||||
retention-days: 1
|
||||
if-no-files-found: error
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue