# leaga_skills.ps1 - expune folderul canonic de agent-skills al ROA catre agenti, fara sa dubleze fisiere. # Creeaza cate un link de director (symlink) pentru fiecare skill din sursa in folderul global # %USERPROFILE%\.claude\skills. Atat Claude Code cat si opencode citesc %USERPROFILE%\.claude\skills\\SKILL.md, # deci un singur set de link-uri serveste ambele gazde. # Link-urile de director cer Developer Mode pe Windows sau o consola de administrator (mklink /D). # Utilizare: # powershell -File COMUN\utile\leaga_skills.ps1 # leaga toate skill-urile # powershell -File COMUN\utile\leaga_skills.ps1 -DryRun # doar listeaza ce ar face # powershell -File COMUN\utile\leaga_skills.ps1 -Force # inlocuieste si link-urile care arata in alta parte param( [string]$Source = (Join-Path $PSScriptRoot '..\skills'), [string]$Target = (Join-Path $env:USERPROFILE '.claude\skills'), [switch]$DryRun, [switch]$Force ) $ErrorActionPreference = 'Stop' function Normalize-Cale { param([string]$Cale) if (-not $Cale) { return '' } ([System.IO.Path]::GetFullPath($Cale)).TrimEnd('\') } function Ia-TintaLink { # PowerShell 5.1 da Target ca string, PowerShell 7 ca lista de string-uri param($Item) $t = $Item.Target if ($t -is [array]) { return ($t | Select-Object -First 1) } return $t } function Sterge-Link { # sterge doar link-ul (reparse point), niciodata continutul din tinta param([string]$Link) try { if (Test-Path -LiteralPath $Link -PathType Container) { [System.IO.Directory]::Delete($Link, $false) } else { Remove-Item -LiteralPath $Link -Force } return $true } catch { return $false } } function Creeaza-Link { # intoarce $true la succes; $script:EroareLink primeste mesajul la esec param([string]$Link, [string]$Dir) $script:EroareLink = '' try { New-Item -ItemType SymbolicLink -Path $Link -Target $Dir -ErrorAction Stop | Out-Null return $true } catch { $script:EroareLink = $_.Exception.Message } $r = & cmd /c mklink /D "$Link" "$Dir" 2>&1 if ($LASTEXITCODE -eq 0) { return $true } $script:EroareLink = (($r | ForEach-Object { [string]$_ }) -join ' ').Trim() return $false } if (-not (Test-Path -LiteralPath $Source -PathType Container)) { Write-Output ('leaga_skills: nu gasesc folderul sursa ' + $Source + ' - nimic de facut.') exit 0 } $skilluri = @(Get-ChildItem -LiteralPath $Source -Directory | Sort-Object Name) if ($skilluri.Count -eq 0) { Write-Output ('leaga_skills: ' + $Source + ' nu contine niciun subfolder de skill - nimic de facut.') exit 0 } if (-not (Test-Path -LiteralPath $Target -PathType Container)) { if ($DryRun) { Write-Output ('DryRun - as crea folderul tinta ' + $Target) } else { New-Item -ItemType Directory -Force -Path $Target | Out-Null Write-Output ('creat folderul tinta ' + $Target) } } $creat = 0; $ok = 0; $atentionat = 0; $anuntPrivilegii = $false foreach ($s in $skilluri) { $dir = $s.FullName $link = Join-Path $Target $s.Name $item = Get-Item -LiteralPath $link -Force -ErrorAction SilentlyContinue if (-not $item) { if ($DryRun) { Write-Output (' ar crea ' + $s.Name + ' -> ' + $dir) $creat++ continue } if (Creeaza-Link -Link $link -Dir $dir) { Write-Output (' creat ' + $s.Name + ' -> ' + $dir) $creat++ } else { Write-Output (' EROARE ' + $s.Name + ' - ' + $script:EroareLink) $atentionat++ if (-not $anuntPrivilegii) { Write-Output ' Link-urile de director cer Windows Developer Mode (Settings > Privacy & security > For developers)' Write-Output ' sau o consola PowerShell pornita ca administrator. Alternativ, copiaza manual folderele de skill.' $anuntPrivilegii = $true } } continue } if ($item.LinkType) { $actual = Normalize-Cale (Ia-TintaLink $item) if ($actual -eq (Normalize-Cale $dir)) { Write-Output (' ok ' + $s.Name + ' (link deja corect)') $ok++ continue } Write-Output ('Atentie: ' + $link + ' arata catre ' + $actual + ', nu catre ' + $dir) if (-not $Force) { Write-Output (' sarit ' + $s.Name + ' - ruleaza cu -Force ca sa il inlocuiesc.') $atentionat++ continue } if ($DryRun) { Write-Output (' ar lega ' + $s.Name + ' (inlocuieste link-ul gresit) -> ' + $dir) $creat++ continue } if (-not (Sterge-Link -Link $link)) { Write-Output (' EROARE ' + $s.Name + ' - nu pot sterge link-ul vechi.') $atentionat++ continue } if (Creeaza-Link -Link $link -Dir $dir) { Write-Output (' refacut ' + $s.Name + ' -> ' + $dir) $creat++ } else { Write-Output (' EROARE ' + $s.Name + ' - ' + $script:EroareLink) $atentionat++ if (-not $anuntPrivilegii) { Write-Output ' Link-urile de director cer Windows Developer Mode (Settings > Privacy & security > For developers)' Write-Output ' sau o consola PowerShell pornita ca administrator.' $anuntPrivilegii = $true } } continue } # nume ocupat de un director/fisier real - nu il atingem niciodata $tip = 'fisier' if ($item.PSIsContainer) { $tip = 'director real' } Write-Output (' sarit ' + $s.Name + ' - ' + $tip + ' exista deja la ' + $link + '; nu il sterg si nu il suprascriu.') $atentionat++ } Write-Output '' if ($DryRun) { Write-Output ('leaga_skills (DryRun): ' + $creat + ' de creat, ' + $ok + ' ok, ' + $atentionat + ' atentionari') } else { Write-Output ('leaga_skills: ' + $creat + ' create, ' + $ok + ' ok, ' + $atentionat + ' atentionari') } exit 0