Last active
December 22, 2025 09:45
-
-
Save netgfx/82efc279d6d0f14e401d645e284894a2 to your computer and use it in GitHub Desktop.
context tunnel - powershell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Tunnel Manager for AI Context (Windows Version) | |
| .DESCRIPTION | |
| Creates or removes symbolic links to external folders to allow AI Agents | |
| to access them as local context. | |
| .EXAMPLE | |
| .\tunnel.ps1 link "C:\Projects\ReferenceRepo" "_TEMPLATE" | |
| .\tunnel.ps1 unlink "_TEMPLATE" | |
| #> | |
| param ( | |
| [Parameter(Mandatory=$true, Position=0)] | |
| [ValidateSet("link", "unlink")] | |
| [string]$Command, | |
| [Parameter(Position=1)] | |
| [string]$SourcePath, | |
| [Parameter(Position=2)] | |
| [string]$TargetName = "TEMPLATE" | |
| ) | |
| # --- Helper for Colors --- | |
| function Log-Info ($msg) { Write-Host "✔ $msg" -ForegroundColor Green } | |
| function Log-Warn ($msg) { Write-Host "⚠ $msg" -ForegroundColor Yellow } | |
| function Log-Error ($msg) { Write-Host "✖ $msg" -ForegroundColor Red } | |
| # --- LINK COMMAND --- | |
| if ($Command -eq "link") { | |
| if ([string]::IsNullOrWhiteSpace($SourcePath)) { | |
| Log-Error "Missing source path. Usage: .\tunnel.ps1 link <path> [name]" | |
| exit 1 | |
| } | |
| # 1. Validate Source | |
| if (-not (Test-Path -Path $SourcePath)) { | |
| Log-Error "Source directory does not exist: $SourcePath" | |
| exit 1 | |
| } | |
| # Get Absolute Path to ensure the link works reliably | |
| $AbsSourcePath = (Resolve-Path $SourcePath).Path | |
| # Check for circular links | |
| $SourceItem = Get-Item -Path $AbsSourcePath -ErrorAction SilentlyContinue | |
| if ($SourceItem.LinkType -eq "SymbolicLink" -or $SourceItem.Attributes -match "ReparsePoint") { | |
| try { | |
| $ResolvedPath = $SourceItem.Target | |
| $CurrentDir = (Get-Location).Path | |
| if ($ResolvedPath -match [regex]::Escape($CurrentDir) -or $ResolvedPath -match [regex]::Escape($TargetName)) { | |
| Log-Error "Creating this link would form a circular dependency." | |
| exit 1 | |
| } | |
| } | |
| catch { | |
| Log-Error "Could not resolve link target." | |
| exit 1 | |
| } | |
| } | |
| # 2. Check if Target already exists | |
| if (Test-Path -Path $TargetName) { | |
| Log-Error "A file or folder named '$TargetName' already exists here." | |
| exit 1 | |
| } | |
| # 3. Create Symlink | |
| try { | |
| New-Item -ItemType SymbolicLink -Path ".\$TargetName" -Target $AbsSourcePath | Out-Null | |
| Log-Info "Linked '$TargetName' -> '$AbsSourcePath'" | |
| } | |
| catch { | |
| Log-Error "Failed to create symlink. Ensure you are running as Administrator or have Developer Mode enabled." | |
| Write-Host $_ | |
| exit 1 | |
| } | |
| # 4. Handle .gitignore | |
| $GitIgnoreFile = ".gitignore" | |
| if (-not (Test-Path $GitIgnoreFile)) { | |
| New-Item $GitIgnoreFile -ItemType File | Out-Null | |
| Log-Warn "Created .gitignore file." | |
| } | |
| # Check if entry exists | |
| $Content = Get-Content $GitIgnoreFile -ErrorAction SilentlyContinue | |
| if ($Content -contains $TargetName) { | |
| Log-Info "'$TargetName' is already in .gitignore" | |
| } | |
| else { | |
| Add-Content -Path $GitIgnoreFile -Value "$TargetName" | |
| Log-Info "Added '$TargetName' to .gitignore" | |
| } | |
| } | |
| # --- UNLINK COMMAND --- | |
| elseif ($Command -eq "unlink") { | |
| # If user ran "unlink", SourcePath might be empty, so we check if they passed a name in pos 1 or 2 | |
| # Logic: if user typed "unlink MyLink", $SourcePath holds "MyLink" because of position. | |
| if (-not [string]::IsNullOrWhiteSpace($SourcePath)) { | |
| $TargetName = $SourcePath | |
| } | |
| # 1. Validate it exists | |
| if (-not (Test-Path -Path $TargetName)) { | |
| Log-Error "'$TargetName' not found." | |
| exit 1 | |
| } | |
| # 2. Validate it is a Symlink/ReparsePoint (Safety Check) | |
| $Item = Get-Item -Path $TargetName | |
| if ($Item.LinkType -ne "SymbolicLink" -and $Item.Attributes -notmatch "ReparsePoint") { | |
| Log-Error "CRITICAL: '$TargetName' is a real directory, not a link!" | |
| Log-Error "Aborting to prevent data loss." | |
| exit 1 | |
| } | |
| # 3. Remove the link | |
| try { | |
| Remove-Item -Path $TargetName -Force | |
| Log-Info "Unlinked '$TargetName'" | |
| } | |
| catch { | |
| Log-Error "Failed to remove link." | |
| Write-Host $_ | |
| exit 1 | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment