Files
comun/utile/leaga_skills.ps1
Marius Mutu d64124386c skills: 9 skill-uri de agent ROA (COMUN\skills) + legare si rutare
- leaga_skills.ps1: expune skill-urile in ~/.claude/skills prin symlink (citit si de Claude Code, si de opencode), fara copiere
- rutare zona->skill in reguli_lucru pct. 7, README, AGENTS.md; skill-ul devine proprietarul procedurii, docurile raman referinta conditionata
- rec_skills.md: decizia, inventarul si cum se adauga un skill nou
2026-09-16 11:54:37 +03:00

163 lines
6.2 KiB
PowerShell

# 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\<nume>\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