| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- # OpenClaw VOC Skills Deploy Script v2.0.0
- #
- # Deploys skills, workshop playbook, and memory templates to OpenClaw
- #
- # Usage:
- # .\deploy-to-openclaw.ps1 # Deploy everything
- # .\deploy-to-openclaw.ps1 -DryRun # Preview only
- # .\deploy-to-openclaw.ps1 -SkillsOnly # Deploy skills only
- # .\deploy-to-openclaw.ps1 -WorkshopOnly # Deploy workshop only
- # .\deploy-to-openclaw.ps1 -OpenClawDir "D:\path" # Custom OpenClaw directory
- param(
- [string]$OpenClawDir = "$env:USERPROFILE\.openclaw",
- [string]$ProjectRoot = (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent),
- [switch]$SkillsOnly,
- [switch]$WorkshopOnly,
- [switch]$DryRun
- )
- $ErrorActionPreference = "Stop"
- $utf8NoBom = New-Object System.Text.UTF8Encoding($false)
- # ============================================
- # Paths
- # ============================================
- $SkillsTarget = Join-Path $OpenClawDir "skills"
- $WorkspaceTarget = Join-Path $OpenClawDir "workspace"
- $MemoryTarget = Join-Path $WorkspaceTarget "memory"
- $SkillCategories = @(
- "voc",
- "social-media",
- "competitor-analysis",
- "review-analysis",
- "synthesis",
- "social-voc",
- "douyin",
- "video-creation",
- "jimeng",
- "payment",
- "test"
- )
- # ============================================
- # Helper Functions
- # ============================================
- function Remove-Bom {
- param([string]$FilePath)
- $bytes = [System.IO.File]::ReadAllBytes($FilePath)
- if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
- $clean = $bytes[3..($bytes.Length - 1)]
- [System.IO.File]::WriteAllBytes($FilePath, $clean)
- return $true
- }
- return $false
- }
- function Test-SkillValid {
- param([string]$SkillDir, [string]$SkillName)
- $skillMd = Join-Path $SkillDir "SKILL.md"
- $apiConf = Join-Path $SkillDir "api-config.json"
- if (-not (Test-Path $skillMd)) {
- Write-Host " [SKIP] $SkillName - missing SKILL.md" -ForegroundColor DarkGray
- return $false
- }
- # Validate YAML frontmatter
- $mdContent = [System.IO.File]::ReadAllText($skillMd, [System.Text.Encoding]::UTF8)
- if ($mdContent -notmatch "^---\s*\r?\n") {
- Write-Host " [WARN] $SkillName - SKILL.md missing YAML frontmatter" -ForegroundColor Yellow
- }
- # Validate api-config.json if exists
- if (Test-Path $apiConf) {
- try {
- $null = Get-Content $apiConf -Raw -Encoding UTF8 | ConvertFrom-Json
- } catch {
- Write-Host " [ERROR] $SkillName - invalid JSON in api-config.json" -ForegroundColor Red
- return $false
- }
- }
- return $true
- }
- function Deploy-File {
- param([string]$Source, [string]$Dest, [string]$Label)
- if ($DryRun) {
- $tag = if (Test-Path $Dest) { "UPDATE" } else { "NEW" }
- Write-Host " [$tag] $Label" -ForegroundColor White
- } else {
- $destDir = Split-Path $Dest -Parent
- if (-not (Test-Path $destDir)) {
- New-Item -ItemType Directory -Path $destDir -Force | Out-Null
- }
- Copy-Item $Source -Destination $Dest -Force
- }
- }
- # ============================================
- # Banner
- # ============================================
- Write-Host ""
- Write-Host " ====================================================" -ForegroundColor Cyan
- Write-Host " OpenClaw VOC Skills Deploy v2.0.0" -ForegroundColor Cyan
- Write-Host " ====================================================" -ForegroundColor Cyan
- Write-Host ""
- Write-Host " Project: $ProjectRoot"
- Write-Host " OpenClaw: $OpenClawDir"
- if ($DryRun) { Write-Host " Mode: DRY RUN (preview only)" -ForegroundColor Yellow }
- if ($SkillsOnly) { Write-Host " Scope: Skills only" -ForegroundColor Yellow }
- if ($WorkshopOnly) { Write-Host " Scope: Workshop only" -ForegroundColor Yellow }
- Write-Host ""
- # Pre-flight check
- if (-not (Test-Path $OpenClawDir)) {
- Write-Host " [ERROR] OpenClaw directory not found: $OpenClawDir" -ForegroundColor Red
- Write-Host " Is OpenClaw installed? Specify -OpenClawDir to override." -ForegroundColor Yellow
- exit 1
- }
- $totalDeployed = 0
- $totalSkipped = 0
- $totalErrors = 0
- $bomFixed = 0
- # ============================================
- # Part 1: Deploy Skills
- # ============================================
- if (-not $WorkshopOnly) {
- Write-Host " [1/3] Deploying Skills" -ForegroundColor Cyan
- Write-Host " $('-' * 48)"
- if (-not $DryRun -and -not (Test-Path $SkillsTarget)) {
- New-Item -ItemType Directory -Path $SkillsTarget -Force | Out-Null
- }
- foreach ($cat in $SkillCategories) {
- $catPath = Join-Path $ProjectRoot $cat
- if (-not (Test-Path $catPath)) { continue }
- $skillDirs = Get-ChildItem -Directory -Path $catPath -ErrorAction SilentlyContinue
- if ($null -eq $skillDirs -or $skillDirs.Count -eq 0) { continue }
- Write-Host " [$cat]" -ForegroundColor DarkCyan
- foreach ($skillDir in $skillDirs) {
- $skillName = $skillDir.Name
- if (-not (Test-SkillValid $skillDir.FullName $skillName)) {
- $totalSkipped++
- continue
- }
- $destDir = Join-Path $SkillsTarget $skillName
- if ($DryRun) {
- $tag = if (Test-Path $destDir) { "UPDATE" } else { "NEW" }
- Write-Host " [$tag] $skillName" -ForegroundColor White
- } else {
- if (Test-Path $destDir) {
- Remove-Item -Recurse -Force $destDir
- }
- New-Item -ItemType Directory -Path $destDir -Force | Out-Null
- Get-ChildItem -File -Path $skillDir.FullName | ForEach-Object {
- Copy-Item $_.FullName -Destination $destDir
- }
- # Fix UTF-8 BOM in SKILL.md (causes OpenClaw parsing failures)
- $deployedMd = Join-Path $destDir "SKILL.md"
- if (Test-Path $deployedMd) {
- if (Remove-Bom $deployedMd) {
- $bomFixed++
- }
- }
- Write-Host " [OK] $skillName" -ForegroundColor Green
- }
- $totalDeployed++
- }
- }
- # Also deploy workshop skills (e.g. brand-context-builder)
- $workshopSkillsPath = Join-Path $ProjectRoot "workshop"
- if (Test-Path $workshopSkillsPath) {
- $wsSkills = Get-ChildItem -Directory -Path $workshopSkillsPath | Where-Object {
- Test-Path (Join-Path $_.FullName "SKILL.md")
- }
- if ($wsSkills.Count -gt 0) {
- Write-Host " [workshop skills]" -ForegroundColor DarkCyan
- foreach ($ws in $wsSkills) {
- $skillName = $ws.Name
- $destDir = Join-Path $SkillsTarget $skillName
- if ($DryRun) {
- $tag = if (Test-Path $destDir) { "UPDATE" } else { "NEW" }
- Write-Host " [$tag] $skillName" -ForegroundColor White
- } else {
- if (Test-Path $destDir) { Remove-Item -Recurse -Force $destDir }
- New-Item -ItemType Directory -Path $destDir -Force | Out-Null
- Get-ChildItem -File -Path $ws.FullName | ForEach-Object {
- Copy-Item $_.FullName -Destination $destDir
- }
- $deployedMd = Join-Path $destDir "SKILL.md"
- if (Test-Path $deployedMd) { if (Remove-Bom $deployedMd) { $bomFixed++ } }
- Write-Host " [OK] $skillName" -ForegroundColor Green
- }
- $totalDeployed++
- }
- }
- }
- Write-Host ""
- }
- # ============================================
- # Part 2: Deploy Workshop Playbook
- # ============================================
- if (-not $SkillsOnly) {
- Write-Host " [2/3] Deploying Workshop Playbook" -ForegroundColor Cyan
- Write-Host " $('-' * 48)"
- $playbookSrc = Join-Path $ProjectRoot "workshop\workshop-voc-playbook.md"
- if (Test-Path $playbookSrc) {
- $playbookDest = Join-Path $WorkspaceTarget "workshop-voc-playbook.md"
- Deploy-File $playbookSrc $playbookDest "workshop-voc-playbook.md"
- if (-not $DryRun) { Write-Host " [OK] workshop-voc-playbook.md" -ForegroundColor Green }
- $totalDeployed++
- } else {
- Write-Host " [SKIP] workshop-voc-playbook.md not found" -ForegroundColor DarkGray
- }
- Write-Host ""
- }
- # ============================================
- # Part 3: Deploy Memory Templates
- # ============================================
- if (-not $SkillsOnly) {
- Write-Host " [3/3] Deploying Memory Templates" -ForegroundColor Cyan
- Write-Host " $('-' * 48)"
- $memSrc = Join-Path $ProjectRoot "workshop\memory-templates"
- if (Test-Path $memSrc) {
- if (-not $DryRun -and -not (Test-Path $MemoryTarget)) {
- New-Item -ItemType Directory -Path $MemoryTarget -Force | Out-Null
- }
- Get-ChildItem -File -Path $memSrc -Filter "*.json" | ForEach-Object {
- $dest = Join-Path $MemoryTarget $_.Name
- Deploy-File $_.FullName $dest $_.Name
- if (-not $DryRun) { Write-Host " [OK] $($_.Name)" -ForegroundColor Green }
- $totalDeployed++
- }
- } else {
- Write-Host " [SKIP] memory-templates directory not found" -ForegroundColor DarkGray
- }
- Write-Host ""
- }
- # ============================================
- # Part 4: Credentials Template
- # ============================================
- if (-not $DryRun -and -not $WorkshopOnly) {
- $credTemplate = Join-Path $ProjectRoot "__config\voc-credentials.template.json"
- $credTarget = Join-Path $OpenClawDir "voc-credentials.template.json"
- $credFile = Join-Path $OpenClawDir "voc-credentials.json"
- if (Test-Path $credTemplate) {
- Copy-Item $credTemplate -Destination $credTarget -Force
- if (-not (Test-Path $credFile)) {
- Write-Host " [INFO] Credentials template copied. Fill in vocToken in:" -ForegroundColor Yellow
- Write-Host " $credFile" -ForegroundColor Yellow
- }
- }
- }
- # ============================================
- # Summary
- # ============================================
- Write-Host " ====================================================" -ForegroundColor Cyan
- Write-Host " Deploy Summary" -ForegroundColor Cyan
- Write-Host " ====================================================" -ForegroundColor Cyan
- Write-Host ""
- Write-Host " Deployed: $totalDeployed"
- Write-Host " Skipped: $totalSkipped"
- Write-Host " Errors: $totalErrors"
- if ($bomFixed -gt 0) {
- Write-Host " BOM fixed: $bomFixed" -ForegroundColor Yellow
- }
- Write-Host ""
- if ($DryRun) {
- Write-Host " Remove -DryRun to execute actual deployment." -ForegroundColor Yellow
- } else {
- Write-Host " Done! Restart OpenClaw gateway to load new skills." -ForegroundColor Green
- Write-Host ""
- Write-Host " Verify:" -ForegroundColor DarkGray
- Write-Host " openclaw skills list" -ForegroundColor DarkGray
- Write-Host " openclaw skills info <skill-name>" -ForegroundColor DarkGray
- }
- Write-Host ""
|