diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 78beb71..d16f396 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -12,7 +12,12 @@
"Bash(done)",
"Bash(for node in idp-control-plane idp-worker idp-worker2)",
"Bash(kubectl --context kind-idp get pods:*)",
- "Bash(kubectl --context kind-idp delete pod:*)"
+ "Bash(kubectl --context kind-idp delete pod:*)",
+ "Bash(grep:*)",
+ "WebFetch(domain:github.com)",
+ "Bash(dotnet build:*)",
+ "Bash(dotnet test:*)",
+ "Bash(test:*)"
]
}
}
diff --git a/cli/src/Vdk/Commands/UpdateClustersCommand.cs b/cli/src/Vdk/Commands/UpdateClustersCommand.cs
index 4a7ec9d..9b2225a 100644
--- a/cli/src/Vdk/Commands/UpdateClustersCommand.cs
+++ b/cli/src/Vdk/Commands/UpdateClustersCommand.cs
@@ -420,7 +420,7 @@ private async Task RolloutRestartDeployment(IKubernetesClient client, V1Deployme
///
/// Checks if a certificate path exists as a directory instead of a file
- /// and removes it. On some systems (especially Mac), Docker may incorrectly
+ /// and removes it. On some systems (especially Mac and WSL2), Docker may incorrectly
/// create directories when mounting paths that don't exist.
///
private void FixCertificatePathIfDirectory(string path, bool verbose)
@@ -436,10 +436,73 @@ private void FixCertificatePathIfDirectory(string path, bool verbose)
_console.WriteLine($"[DEBUG] Successfully removed directory '{path}'");
}
}
- catch (Exception ex)
+ catch (Exception)
{
- _console.WriteError($"Failed to remove directory '{path}': {ex.Message}");
+ // On WSL2/Linux, directories created by Docker may have root ownership.
+ // Fall back to shell command with elevated permissions.
+ if (TryRemoveDirectoryWithShell(path, verbose))
+ {
+ if (verbose)
+ {
+ _console.WriteLine($"[DEBUG] Successfully removed directory '{path}' using shell command");
+ }
+ }
+ else
+ {
+ _console.WriteError($"Failed to remove directory '{path}'. Try running: sudo rm -rf \"{path}\"");
+ }
}
}
}
+
+ ///
+ /// Attempts to remove a directory using shell commands, which may succeed
+ /// when .NET Directory.Delete fails due to permission issues.
+ ///
+ private bool TryRemoveDirectoryWithShell(string path, bool verbose)
+ {
+ try
+ {
+ var isWindows = System.OperatingSystem.IsWindows();
+ var startInfo = new System.Diagnostics.ProcessStartInfo
+ {
+ FileName = isWindows ? "cmd.exe" : "/bin/sh",
+ Arguments = isWindows
+ ? $"/c rmdir /s /q \"{path}\""
+ : $"-c \"rm -rf '{path}'\"",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true
+ };
+
+ using var process = System.Diagnostics.Process.Start(startInfo);
+ process?.WaitForExit(5000);
+
+ // Check if directory was actually removed
+ if (!_fileSystem.Directory.Exists(path))
+ {
+ return true;
+ }
+
+ // If still exists, try with sudo on Linux/Mac
+ if (!isWindows)
+ {
+ if (verbose)
+ {
+ _console.WriteLine($"[DEBUG] Attempting sudo rm -rf for '{path}'");
+ }
+ startInfo.Arguments = $"-c \"sudo rm -rf '{path}'\"";
+ using var sudoProcess = System.Diagnostics.Process.Start(startInfo);
+ sudoProcess?.WaitForExit(10000);
+ return !_fileSystem.Directory.Exists(path);
+ }
+
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
}
diff --git a/cli/src/Vdk/Services/DockerHubClient.cs b/cli/src/Vdk/Services/DockerHubClient.cs
index d7703ee..f3966db 100644
--- a/cli/src/Vdk/Services/DockerHubClient.cs
+++ b/cli/src/Vdk/Services/DockerHubClient.cs
@@ -15,6 +15,67 @@ public void CreateRegistry()
var configFile = new FileInfo(Path.Combine("ConfigMounts", "zot-config.json"));
var imagesDir = new DirectoryInfo("images");
+ // Ensure ConfigMounts directory exists
+ var configMountsDir = configFile.Directory;
+ if (configMountsDir != null && !configMountsDir.Exists)
+ {
+ configMountsDir.Create();
+ }
+
+ // Fix: Check if config file was incorrectly created as a directory by Docker
+ if (Directory.Exists(configFile.FullName))
+ {
+ console.WriteLine($"Config path '{configFile.FullName}' exists as a directory instead of a file. Removing...");
+ Directory.Delete(configFile.FullName, recursive: true);
+ }
+
+ // Ensure config file exists - try to copy from app directory or create default
+ if (!configFile.Exists)
+ {
+ // Try to find config in application base directory
+ var appBaseConfig = Path.Combine(AppContext.BaseDirectory, "ConfigMounts", "zot-config.json");
+ if (File.Exists(appBaseConfig))
+ {
+ console.WriteLine($"Copying zot config from {appBaseConfig}");
+ File.Copy(appBaseConfig, configFile.FullName);
+ }
+ else
+ {
+ // Create default config
+ console.WriteLine("Creating default zot-config.json");
+ var defaultConfig = """
+ {
+ "distSpecVersion": "1.1.0",
+ "storage": {
+ "rootDirectory": "/var/lib/registry",
+ "gc": true,
+ "gcDelay": "1h",
+ "gcInterval": "24h"
+ },
+ "http": {
+ "address": "0.0.0.0",
+ "port": "5000"
+ },
+ "log": {
+ "level": "info"
+ },
+ "extensions": {
+ "ui": {
+ "enable": true
+ },
+ "search": {
+ "enable": true,
+ "cve": {
+ "updateInterval": "24h"
+ }
+ }
+ }
+ }
+ """;
+ File.WriteAllText(configFile.FullName, defaultConfig);
+ }
+ }
+
// Ensure images directory exists
if (!imagesDir.Exists)
{
diff --git a/cli/src/Vdk/Services/FallbackDockerEngine.cs b/cli/src/Vdk/Services/FallbackDockerEngine.cs
index a93c7fa..c4fd7c3 100644
--- a/cli/src/Vdk/Services/FallbackDockerEngine.cs
+++ b/cli/src/Vdk/Services/FallbackDockerEngine.cs
@@ -25,6 +25,16 @@ internal static bool RunProcess(string fileName, string arguments, out string st
public bool Run(string image, string name, PortMapping[]? ports, Dictionary? envs, FileMapping[]? volumes, string[]? commands, string? network = null)
{
+ // Validate and fix volume mount sources before creating container
+ // This prevents Docker from creating directories when files are expected
+ if (volumes != null)
+ {
+ foreach (var volume in volumes)
+ {
+ EnsureVolumeMountSource(volume.Source, volume.Destination);
+ }
+ }
+
var args = $"run -d --name {name}";
if (network != null)
args += $" --network {network}";
@@ -53,6 +63,54 @@ public bool Run(string image, string name, PortMapping[]? ports, Dictionary
+ /// Ensures that a volume mount source path exists correctly.
+ /// Fixes the common Docker issue where mounting a non-existent file creates a directory instead.
+ ///
+ private void EnsureVolumeMountSource(string sourcePath, string destinationPath)
+ {
+ // Determine if destination looks like a file (has extension) or directory
+ bool isFilePath = Path.HasExtension(destinationPath) && !destinationPath.EndsWith('/') && !destinationPath.EndsWith('\\');
+
+ // Check if path was incorrectly created as a directory when it should be a file
+ if (isFilePath && Directory.Exists(sourcePath))
+ {
+ Console.WriteLine($"Mount path '{sourcePath}' exists as a directory instead of a file. Removing...");
+ try
+ {
+ Directory.Delete(sourcePath, recursive: true);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException(
+ $"Failed to remove directory '{sourcePath}': {ex.Message}",
+ ex);
+ }
+ }
+
+ // Ensure parent directory exists
+ var parentDir = Path.GetDirectoryName(sourcePath);
+ if (!string.IsNullOrEmpty(parentDir) && !Directory.Exists(parentDir))
+ {
+ Directory.CreateDirectory(parentDir);
+ }
+
+ // For file paths, ensure the file exists
+ if (isFilePath && !File.Exists(sourcePath))
+ {
+ throw new FileNotFoundException(
+ $"Mount source file does not exist: '{sourcePath}'. " +
+ $"Please ensure the required config file exists before running this command.",
+ sourcePath);
+ }
+
+ // For directory paths, ensure directory exists
+ if (!isFilePath && !Directory.Exists(sourcePath))
+ {
+ Directory.CreateDirectory(sourcePath);
+ }
+ }
+
public bool Exists(string name, bool checkRunning = true)
{
var filter = checkRunning ? "--filter \"status=running\"" : "";
diff --git a/cli/src/Vdk/Services/LocalDockerClient.cs b/cli/src/Vdk/Services/LocalDockerClient.cs
index 48a92c5..da31a35 100644
--- a/cli/src/Vdk/Services/LocalDockerClient.cs
+++ b/cli/src/Vdk/Services/LocalDockerClient.cs
@@ -14,6 +14,16 @@ public LocalDockerClient(Docker.DotNet.IDockerClient dockerClient)
public bool Run(string image, string name, PortMapping[]? ports, Dictionary? envs, FileMapping[]? volumes, string[]? commands, string? network = null)
{
+ // Validate and fix volume mount sources before creating container
+ // This prevents Docker from creating directories when files are expected
+ if (volumes != null)
+ {
+ foreach (var volume in volumes)
+ {
+ EnsureVolumeMountSource(volume.Source, volume.Destination);
+ }
+ }
+
_dockerClient.Images.CreateImageAsync(
new ImagesCreateParameters
{
@@ -160,4 +170,52 @@ public bool CanConnect()
return false;
}
}
+
+ ///
+ /// Ensures that a volume mount source path exists correctly.
+ /// Fixes the common Docker issue where mounting a non-existent file creates a directory instead.
+ ///
+ private void EnsureVolumeMountSource(string sourcePath, string destinationPath)
+ {
+ // Determine if destination looks like a file (has extension) or directory
+ bool isFilePath = Path.HasExtension(destinationPath) && !destinationPath.EndsWith('/') && !destinationPath.EndsWith('\\');
+
+ // Check if path was incorrectly created as a directory when it should be a file
+ if (isFilePath && Directory.Exists(sourcePath))
+ {
+ Console.WriteLine($"Certificate path '{sourcePath}' exists as a directory instead of a file. Removing...");
+ try
+ {
+ Directory.Delete(sourcePath, recursive: true);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException(
+ $"Failed to remove directory '{sourcePath}': {ex.Message}",
+ ex);
+ }
+ }
+
+ // Ensure parent directory exists
+ var parentDir = Path.GetDirectoryName(sourcePath);
+ if (!string.IsNullOrEmpty(parentDir) && !Directory.Exists(parentDir))
+ {
+ Directory.CreateDirectory(parentDir);
+ }
+
+ // For file paths, ensure the file exists
+ if (isFilePath && !File.Exists(sourcePath))
+ {
+ throw new FileNotFoundException(
+ $"Mount source file does not exist: '{sourcePath}'. " +
+ $"Please ensure the required config file exists before running this command.",
+ sourcePath);
+ }
+
+ // For directory paths, ensure directory exists
+ if (!isFilePath && !Directory.Exists(sourcePath))
+ {
+ Directory.CreateDirectory(sourcePath);
+ }
+ }
}
\ No newline at end of file
diff --git a/cli/src/Vdk/Services/ReverseProxyClient.cs b/cli/src/Vdk/Services/ReverseProxyClient.cs
index fb3431c..563c3cd 100644
--- a/cli/src/Vdk/Services/ReverseProxyClient.cs
+++ b/cli/src/Vdk/Services/ReverseProxyClient.cs
@@ -85,6 +85,8 @@ public void Create()
!ValidateAndFixCertificatePath(privKey.FullName))
{
_console.WriteError("Certificate files are missing. Please ensure Certs/fullchain.pem and Certs/privkey.pem exist.");
+ _console.WriteError("If using the init.sh installer, certificates should be in the Certs/ folder relative to where you run vega.");
+ _console.WriteError("You may need to copy them from .bin/ to your project root: cp -r .bin/Certs ./Certs");
return;
}
@@ -109,7 +111,7 @@ public void Create()
///
/// Validates a certificate path exists as a file, not a directory.
- /// On some systems (especially Mac), Docker may incorrectly create directories
+ /// On some systems (especially Mac and WSL2), Docker may incorrectly create directories
/// when mounting paths that don't exist. This method detects and removes such directories.
///
private bool ValidateAndFixCertificatePath(string path)
@@ -122,10 +124,15 @@ private bool ValidateAndFixCertificatePath(string path)
{
Directory.Delete(path, recursive: true);
}
- catch (Exception ex)
+ catch (Exception)
{
- _console.WriteError($"Failed to remove directory '{path}': {ex.Message}");
- return false;
+ // On WSL2/Linux, directories created by Docker may have root ownership.
+ // Fall back to shell command with elevated permissions.
+ if (!TryRemoveDirectoryWithShell(path))
+ {
+ _console.WriteError($"Failed to remove directory '{path}'. Try running: sudo rm -rf \"{path}\"");
+ return false;
+ }
}
}
@@ -133,6 +140,53 @@ private bool ValidateAndFixCertificatePath(string path)
return File.Exists(path);
}
+ ///
+ /// Attempts to remove a directory using shell commands, which may succeed
+ /// when .NET Directory.Delete fails due to permission issues.
+ ///
+ private bool TryRemoveDirectoryWithShell(string path)
+ {
+ try
+ {
+ var isWindows = System.OperatingSystem.IsWindows();
+ var startInfo = new System.Diagnostics.ProcessStartInfo
+ {
+ FileName = isWindows ? "cmd.exe" : "/bin/sh",
+ Arguments = isWindows
+ ? $"/c rmdir /s /q \"{path}\""
+ : $"-c \"rm -rf '{path}'\"",
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true
+ };
+
+ using var process = System.Diagnostics.Process.Start(startInfo);
+ process?.WaitForExit(5000);
+
+ // Check if directory was actually removed
+ if (!Directory.Exists(path))
+ {
+ return true;
+ }
+
+ // If still exists, try with sudo on Linux/Mac
+ if (!isWindows)
+ {
+ startInfo.Arguments = $"-c \"sudo rm -rf '{path}'\"";
+ using var sudoProcess = System.Diagnostics.Process.Start(startInfo);
+ sudoProcess?.WaitForExit(10000);
+ return !Directory.Exists(path);
+ }
+
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
public bool Exists()
{
try
@@ -365,6 +419,7 @@ private bool CreateTlsSecret(string clusterName)
!ValidateAndFixCertificatePath(privKeyPath))
{
_console.WriteError("Certificate files are missing. Cannot create TLS secret.");
+ _console.WriteError("Ensure Certs/fullchain.pem and Certs/privkey.pem exist in your project directory.");
return true;
}
diff --git a/init.sh b/init.sh
index 0a716fd..de3c357 100755
--- a/init.sh
+++ b/init.sh
@@ -1,61 +1,180 @@
-# /bin/bash
-if groups $USER | grep -q "\bdocker\b"; then
- echo "Welcome to Vega VDK"
- # Variables
- REPO="ArchetypicalSoftware/VDK" # Replace with your GitHub repository (e.g., username/repo)
- TOKEN=$GITHUB_VDK_TOKEN # Replace with your GitHub Personal Access Token
- ASSET_NAME="vega-linux-x64.tar.gz" # Replace with the asset name you're looking for
- DOWNLOAD_DIR="./.bin" # Specify the download directory
-
- # Get the latest release information
- echo "Fetching the latest release information..."
- LATEST_RELEASE=$(curl -s -H "Authorization: token $TOKEN" "https://api.github.com/repos/$REPO/releases/latest")
- VERSION=$(echo "$LATEST_RELEASE" | jq -r ".tag_name")
- CURRENT=$(cat ./.bin/vdk.version)
- if [ "$VERSION" != "$CURRENT" ]; then
- # Extract the asset ID for the desired asset
- ASSET_ID=$(echo "$LATEST_RELEASE" | jq -r ".assets[] | select(.name == \"$ASSET_NAME\") | .id")
-
- if [ -z "$ASSET_ID" ]; then
- echo "Error: Asset \"$ASSET_NAME\" not found in the latest release."
- exit 1
+#!/bin/bash
+# Docker permissions hardening for Linux and macOS
+OS_TYPE=$(uname -s | tr '[:upper:]' '[:lower:]')
+
+if [ "$OS_TYPE" = "linux" ]; then
+ if ! getent group docker > /dev/null 2>&1; then
+ echo "[INFO] Creating 'docker' group (requires sudo)"
+ sudo groupadd docker
+ fi
+ if ! groups $USER | grep -q '\bdocker\b'; then
+ echo "[INFO] Adding user $USER to 'docker' group (requires sudo)"
+ sudo usermod -aG docker "$USER"
+ echo "[INFO] Please exit and restart your shell to pick up group membership changes."
+ exit 0
+ fi
+ if ! command -v docker >/dev/null 2>&1; then
+ echo "[ERROR] Docker CLI is not installed. Please install Docker before proceeding."
+ exit 1
+ fi
+ echo "[SUCCESS] Docker permissions are set up for $USER."
+elif [ "$OS_TYPE" = "darwin" ]; then
+ if ! command -v docker >/dev/null 2>&1; then
+ echo "[ERROR] Docker CLI is not installed. Please install Docker Desktop for Mac."
+ exit 1
+ fi
+ # Check if Docker Desktop is running
+ if ! docker info >/dev/null 2>&1; then
+ echo "[ERROR] Docker Desktop does not appear to be running. Please start Docker Desktop."
+ exit 1
+ fi
+ echo "[SUCCESS] Docker is available on macOS."
+else
+ echo "[ERROR] Unsupported OS: $OS_TYPE. This script supports only Linux and macOS."
+ exit 1
+fi
+
+echo "Welcome to Vega VDK"
+# Variables
+REPO="ArchetypicalSoftware/VDK"
+DOWNLOAD_DIR="./.bin"
+
+UNAME_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
+UNAME_ARCH=$(uname -m)
+case "$UNAME_OS" in
+ linux)
+ RID_OS="linux" ;;
+ darwin)
+ RID_OS="osx" ;;
+ *)
+ echo "Unsupported OS: $UNAME_OS"
+ exit 1 ;;
+esac
+
+case "$UNAME_ARCH" in
+ x86_64|amd64)
+ RID_ARCH="x64" ;;
+ arm64|aarch64)
+ RID_ARCH="arm64" ;;
+ *)
+ echo "Unsupported architecture: $UNAME_ARCH"
+ exit 1 ;;
+esac
+
+RID="$RID_OS-$RID_ARCH"
+ASSET_NAME="vega-$RID.tar.gz"
+
+echo "Fetching the latest release information..."
+LATEST_RELEASE=$(curl -s "https://api.github.com/repos/$REPO/releases/latest")
+VERSION=$(echo "$LATEST_RELEASE" | jq -r ".tag_name")
+CURRENT=$(cat ./.bin/vdk.version 2>/dev/null)
+if [ "$VERSION" != "$CURRENT" ]; then
+ ASSET_URL=$(echo "$LATEST_RELEASE" | jq -r ".assets[] | select(.name == \"$ASSET_NAME\") | .browser_download_url")
+
+ if [ -z "$ASSET_URL" ] || [ "$ASSET_URL" == "null" ]; then
+ echo "Error: Asset for OS '$OS' and arch '$ARCH' (expected name: $ASSET_NAME) not found in the latest release."
+ exit 1
+ fi
+
+ mkdir -p "$DOWNLOAD_DIR"
+
+ echo "Downloading asset \"$ASSET_NAME\"..."
+ curl -L "$ASSET_URL" -o "$DOWNLOAD_DIR/$ASSET_NAME"
+
+ echo "Download complete! File saved to \"$DOWNLOAD_DIR/$ASSET_NAME\""
+ echo "Extracting Vega CLI..."
+ tar --overwrite -xvf "$DOWNLOAD_DIR/$ASSET_NAME" -C "$DOWNLOAD_DIR"
+
+ # Move vega binary to .bin root
+ FOUND_VEGA=$(find "$DOWNLOAD_DIR" -type f -name vega | head -n 1)
+ if [ -n "$FOUND_VEGA" ]; then
+ if [ "$FOUND_VEGA" != "./.bin/vega" ]; then
+ mv -f "$FOUND_VEGA" ./.bin/vega
+ echo "[INFO] Vega binary moved to ./.bin/vega"
+ else
+ echo "[INFO] Vega binary already in ./.bin/vega"
fi
+ else
+ echo "[WARNING] Vega binary not found after extraction."
+ fi
- # Create the download directory if it doesn't exist
- mkdir -p "$DOWNLOAD_DIR"
-
- # Download the asset
- echo "Downloading asset \"$ASSET_NAME\"..."
- curl -L -H "Authorization: token $TOKEN" \
- -H "Accept: application/octet-stream" \
- "https://api.github.com/repos/$REPO/releases/assets/$ASSET_ID" \
- -o "$DOWNLOAD_DIR/$ASSET_NAME"
-
- echo "Download complete! File saved to \"$DOWNLOAD_DIR/$ASSET_NAME\""
- echo "Extracting Vega CLI..."
- tar --overwrite -xvf "$DOWNLOAD_DIR/$ASSET_NAME" -C "$DOWNLOAD_DIR"
- mv -f "$DOWNLOAD_DIR/packages/build/linux-x64/vega" ./.bin/vega
- rm -rf "$DOWNLOAD_DIR/packages"
- rm "$DOWNLOAD_DIR/$ASSET_NAME"
- echo "$VERSION" > "$DOWNLOAD_DIR/vdk.version"
- echo "Version: $VERSION"
+ # Copy Certs folder to project root (required for TLS)
+ # This prevents Docker from creating directories when mounting non-existent cert files
+ FOUND_CERTS=$(find "$DOWNLOAD_DIR" -type d -name Certs | head -n 1)
+ if [ -n "$FOUND_CERTS" ] && [ -d "$FOUND_CERTS" ]; then
+ # Remove any incorrectly created directories from previous Docker runs
+ if [ -d "./Certs/fullchain.pem" ]; then
+ echo "[INFO] Removing incorrectly created directory ./Certs/fullchain.pem"
+ rm -rf "./Certs/fullchain.pem" 2>/dev/null || sudo rm -rf "./Certs/fullchain.pem"
+ fi
+ if [ -d "./Certs/privkey.pem" ]; then
+ echo "[INFO] Removing incorrectly created directory ./Certs/privkey.pem"
+ rm -rf "./Certs/privkey.pem" 2>/dev/null || sudo rm -rf "./Certs/privkey.pem"
+ fi
+ mkdir -p ./Certs
+ cp -f "$FOUND_CERTS"/* ./Certs/ 2>/dev/null
+ echo "[INFO] Certificates copied to ./Certs/"
else
- echo "Version: $CURRENT"
- fi
- cd ./.bin
- BIN_PATH=$(pwd)
- cd ..
- # echo "$PATH" | grep -q $BIN_PATH
- # if [ $? -ne 0 ]; then
- # echo "Updating Path"
- # echo >> ~/.bashrc && echo "export PATH='$PATH:$BIN_PATH'" >> ~/.bashrc && source ~/.bashrc
- # fi
+ echo "[WARNING] Certs folder not found in extraction. TLS features may not work."
+ fi
+
+ # Copy ConfigMounts folder to project root (required for container registry)
+ FOUND_CONFIGMOUNTS=$(find "$DOWNLOAD_DIR" -type d -name ConfigMounts | head -n 1)
+ if [ -n "$FOUND_CONFIGMOUNTS" ] && [ -d "$FOUND_CONFIGMOUNTS" ]; then
+ mkdir -p ./ConfigMounts
+ cp -f "$FOUND_CONFIGMOUNTS"/* ./ConfigMounts/ 2>/dev/null
+ echo "[INFO] ConfigMounts copied to ./ConfigMounts/"
+ fi
+
+ rm "$DOWNLOAD_DIR/$ASSET_NAME"
+ echo "$VERSION" > "$DOWNLOAD_DIR/vdk.version"
+ echo "Version: $VERSION"
else
- echo "Adding user $USER to docker group"
- echo " (This will require sudo access)"
- sudo usermod -aG docker "$USER"
- echo "Please exit and restart your shell to pick up group membership changes."
+ echo "Version: $CURRENT"
+fi
+
+cd ./.bin
+BIN_PATH=$(pwd)
+cd ..
+echo "$PATH" | grep -q $BIN_PATH
+if [ $? -ne 0 ]; then
+ echo "[INFO] Adding $BIN_PATH to PATH for this session."
+ export PATH="$PATH:$BIN_PATH"
fi
-# sudo gpasswd -d username groupname
-# sudo gpasswd -d $USER docker
\ No newline at end of file
+if command -v vega >/dev/null 2>&1; then
+ echo "[INFO] Vega CLI version output:"
+ VEGA_OUT="$(vega --version 2>&1)"
+ VEGA_EXIT=$?
+ echo "$VEGA_OUT"
+ if [ "$OS_TYPE" = "darwin" ]; then
+ MAC_ARCH=$(uname -m)
+ BIN_ARCH=$(file .bin/vega | grep -oE 'arm64|x86_64')
+ if [ "$MAC_ARCH" = "arm64" ] && [ "$BIN_ARCH" = "x86_64" ]; then
+ echo "[WARNING] You are running an x64 binary on Apple Silicon. Try installing Rosetta: sudo softwareupdate --install-rosetta, or use the osx-arm64 build."
+ elif [ "$MAC_ARCH" = "x86_64" ] && [ "$BIN_ARCH" = "arm64" ]; then
+ echo "[ERROR] You are running an ARM64 binary on an Intel Mac. Use the osx-x64 build."
+ fi
+
+ MISSING_SWIFT=0
+ for LIB in libswiftCore.dylib libswiftFoundation.dylib; do
+ if ! otool -L .bin/vega | grep -q "$LIB"; then
+ MISSING_SWIFT=1
+ fi
+ done
+ if [ $MISSING_SWIFT -eq 1 ]; then
+ echo "[WARNING] Vega CLI may require the Swift runtime. Install Xcode or Xcode Command Line Tools: xcode-select --install"
+ fi
+
+ if echo "$VEGA_OUT" | grep -qi 'killed' || [ $VEGA_EXIT -ne 0 ]; then
+ echo "[ERROR] Vega CLI failed to run. Suggestions:"
+ echo "- Ensure you are using the correct binary for your architecture."
+ echo "- Try installing Rosetta (for x64 on Apple Silicon): sudo softwareupdate --install-rosetta"
+ echo "- Install Xcode or Xcode Command Line Tools for Swift runtime."
+ echo "- Check for missing libraries: otool -L .bin/vega"
+ echo "- For more details, check system logs: log show --predicate 'process == \"vega\"' --info --last 1h"
+ fi
+ fi
+else
+ echo "[WARNING] Vega CLI not found in PATH or not executable."
+fi