fix: correct CLI installation verification after title mode args update (#153)

* fix: correct CLI installation verification after title mode args update (#153)

• Verify CLI install by matching `exec "$VIBETUNNEL_BIN" fwd` (ignores extra args) — resolves #152  
• Allow custom install dir (default `/usr/local/bin`); `vtTargetPath` now dynamic  
• Added regression + flaky-test fix
This commit is contained in:
Igor Tarasenko 2025-07-01 07:09:43 +02:00 committed by GitHub
parent 4bdb21da41
commit 68ce36828a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 47 additions and 8 deletions

View file

@ -27,28 +27,40 @@ final class CLIInstaller {
// MARK: - Properties
private let logger = Logger(subsystem: "sh.vibetunnel.vibetunnel", category: "CLIInstaller")
private let binDirectory: String
private var vtTargetPath: String {
URL(fileURLWithPath: binDirectory).appendingPathComponent("vt").path
}
var isInstalled = false
var isInstalling = false
var lastError: String?
// MARK: - Initialization
/// Creates a CLI installer
/// - Parameters:
/// - binDirectory: Directory for installation (defaults to /usr/local/bin)
init(binDirectory: String = "/usr/local/bin") {
self.binDirectory = binDirectory
}
// MARK: - Public Interface
/// Checks if the CLI tool is installed
func checkInstallationStatus() {
Task { @MainActor in
let vtPath = "/usr/local/bin/vt"
// Check if vt script exists and is configured correctly
var isCorrectlyInstalled = false
if FileManager.default.fileExists(atPath: vtPath) {
if FileManager.default.fileExists(atPath: vtTargetPath) {
// Check if it contains the correct app path reference
if let content = try? String(contentsOfFile: vtPath, encoding: .utf8) {
if let content = try? String(contentsOfFile: vtTargetPath, encoding: .utf8) {
// Verify it's our wrapper script with all expected components
isCorrectlyInstalled = content.contains("VibeTunnel CLI wrapper") &&
content.contains("$TRY_PATH/Contents/Resources/vibetunnel") &&
content.contains("exec \"$VIBETUNNEL_BIN\" fwd \"$@\"")
content.contains("exec \"$VIBETUNNEL_BIN\" fwd")
}
}
@ -117,9 +129,6 @@ final class CLIInstaller {
return
}
let vtTargetPath = "/usr/local/bin/vt"
let binDirectory = "/usr/local/bin"
// Create the installation script
let script = """
#!/bin/bash

View file

@ -416,4 +416,34 @@ struct CLIInstallerTests {
await installer.install()
#expect(installer.isInstalled)
}
// MARK: - PR #153 Regression Test
@Test("Script with TITLE_MODE_ARGS detected correctly", .tags(.regression))
func scriptWithTitleModeArgsDetection() async throws {
let script = """
#!/bin/bash
# VibeTunnel CLI wrapper
for TRY_PATH in "/Applications/VibeTunnel.app" "$HOME/Applications/VibeTunnel.app"; do
if [ -d "$TRY_PATH" ] && [ -f "$TRY_PATH/Contents/Resources/vibetunnel" ]; then
APP_PATH="$TRY_PATH"
break
fi
done
VIBETUNNEL_BIN="$APP_PATH/Contents/Resources/vibetunnel"
TITLE_MODE_ARGS="--title-mode dynamic"
exec "$VIBETUNNEL_BIN" fwd $TITLE_MODE_ARGS "$@"
"""
let vtPath = tempDirectory.appendingPathComponent("vt").path
try script.write(toFile: vtPath, atomically: true, encoding: .utf8)
let installer = CLIInstaller(binDirectory: tempDirectory.path)
installer.checkInstallationStatus()
// Wait for the async Task in checkInstallationStatus to complete
try await Task.sleep(for: .milliseconds(100))
#expect(installer.isInstalled)
}
}