Files
draft-closing-report-default/tools/scaffold_skill.ps1
chenfuqiang 7b24521b43
All checks were successful
技能自动化发布 / release (push) Successful in 6s
feat: 结题报告初稿助手首版 v1.0.1(draft-closing-report-default)
2026-09-13 16:04:01 +08:00

141 lines
4.6 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#Requires -Version 5.1
<#
.SYNOPSIS
Scaffold a new skill directory from skill-template (excludes .git).
.EXAMPLE
.\tools\scaffold_skill.ps1 -Slug my-new-skill -Destination D:\OpenClaw\client-gdcm\my-new-skill
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Slug,
[Parameter(Mandatory = $true)]
[string]$Destination,
[switch]$Force
)
$ErrorActionPreference = "Stop"
function Test-KebabSlug([string]$Value) {
return $Value -match '^[a-z0-9]+(-[a-z0-9]+)*$'
}
function Write-ScaffoldNextSteps([string]$TargetPath) {
Write-Host ""
Write-Host "=== 脚手架复制完成 ===" -ForegroundColor Green
Write-Host ("目标目录: " + $TargetPath)
Write-Host ""
Write-Host "请在本机继续执行(未自动 git init,避免误操作):" -ForegroundColor Yellow
Write-Host (' cd "' + $TargetPath + '"')
Write-Host " Remove-Item -Recurse -Force .git -ErrorAction SilentlyContinue"
Write-Host " git init"
Write-Host " git remote add origin <你的新技能仓库 URL>"
Write-Host " git remote -v"
Write-Host " # 确认 assets/actions.json 中 skill 已替换为新 slug;不需要 Action 时可删除该文件"
Write-Host " python tests/run_tests.py -v"
Write-Host ""
}
$TemplateRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
$TargetPath = $Destination
if (-not (Test-KebabSlug $Slug)) {
throw "Slug must be kebab-case. Got: $Slug"
}
$leaf = Split-Path -Leaf ($TargetPath.TrimEnd('\', '/'))
if ($leaf -ne $Slug) {
throw "Destination leaf '$leaf' must match -Slug '$Slug'."
}
$parent = Split-Path -Parent $TargetPath
if (-not $parent -or -not (Test-Path -LiteralPath $parent)) {
throw "Parent directory does not exist: $parent"
}
$gitPath = Join-Path $TargetPath ".git"
if (Test-Path -LiteralPath $gitPath) {
throw "Target already has .git at $gitPath . Remove it first or use an empty destination."
}
$targetExists = Test-Path -LiteralPath $TargetPath
if ($targetExists) {
$entries = @(Get-ChildItem -LiteralPath $TargetPath -Force -ErrorAction SilentlyContinue)
if ($entries.Count -gt 0 -and -not $Force) {
throw "Target exists and is not empty: $TargetPath . Use -Force or pick an empty directory."
}
}
$excludeDirs = @(".git", ".pytest_cache", "__pycache__")
$excludeFiles = @(".env", ".env.local")
$templatePlaceholderSlugKebab = "your-skill-slug"
$templatePlaceholderSlugUnderscore = "your_skill_slug"
$textFileSuffixes = @(".md", ".py", ".json", ".yaml", ".yml", ".txt", ".ini", ".ps1", ".sample")
function Copy-TemplateTree {
param(
[string]$Source,
[string]$Dest
)
if (-not (Test-Path -LiteralPath $Dest)) {
New-Item -ItemType Directory -Path $Dest -Force | Out-Null
}
Get-ChildItem -LiteralPath $Source -Force | ForEach-Object {
$name = $_.Name
if ($excludeDirs -contains $name) { return }
if ($excludeFiles -contains $name) { return }
if ($name -like "*.pyc") { return }
$srcPath = $_.FullName
$dstPath = Join-Path $Dest $name
if ($_.PSIsContainer) {
Copy-TemplateTree -Source $srcPath -Dest $dstPath
}
else {
Copy-Item -LiteralPath $srcPath -Destination $dstPath -Force
}
}
}
function Replace-TemplatePlaceholders {
param(
[string]$Root,
[string]$Slug
)
$underscoreSlug = $Slug.Replace("-", "_")
Get-ChildItem -LiteralPath $Root -Recurse -File -Force | ForEach-Object {
$name = $_.Name
if ($excludeFiles -contains $name) { return }
$ext = $_.Extension.ToLowerInvariant()
if ($textFileSuffixes -notcontains $ext -and $name -ne ".env.example") { return }
try {
$text = [System.IO.File]::ReadAllText($_.FullName)
}
catch {
return
}
if (
$text -notlike "*$templatePlaceholderSlugKebab*" -and
$text -notlike "*$templatePlaceholderSlugUnderscore*"
) { return }
$updated = $text.Replace($templatePlaceholderSlugKebab, $Slug)
$updated = $updated.Replace($templatePlaceholderSlugUnderscore, $underscoreSlug)
[System.IO.File]::WriteAllText($_.FullName, $updated)
}
}
Write-Host "Copy template: $TemplateRoot -> $TargetPath" -ForegroundColor Cyan
Copy-TemplateTree -Source $TemplateRoot -Dest $TargetPath
$marker = Join-Path $TargetPath ".openclaw-skill-template"
if (Test-Path -LiteralPath $marker) {
Remove-Item -LiteralPath $marker -Force
}
Replace-TemplatePlaceholders -Root $TargetPath -Slug $Slug
Write-ScaffoldNextSteps -TargetPath (Resolve-Path -LiteralPath $TargetPath).Path