param(
[string]$Skill = "",
[switch]$Force = $false,
[switch]$Uninstall = $false,
[switch]$Update = $false,
[switch]$Claude = $false,
[switch]$Cursor = $false,
[switch]$Codex = $false,
[switch]$Cline = $false,
[switch]$OpenCode = $false,
[switch]$Copilot = $false,
[switch]$Trae = $false,
[switch]$OpenClaw = $false,
[switch]$Hermes = $false,
[switch]$Help = $false
)
if ($Help) {
Write-Host "用法: install.bat [工具名] [选项]"
Write-Host ""
Write-Host " 无参数 自动检测 agent,安装 skills\ 下所有工具"
Write-Host " ascend-kg 仅安装指定工具"
Write-Host " -Force 覆盖已有安装"
Write-Host " -Uninstall 卸载"
Write-Host " -Update 更新(git pull + 覆盖重装)"
Write-Host " -Claude 仅操作 Claude Code"
Write-Host " -Cursor 仅操作 Cursor"
Write-Host " -Codex 仅操作 Codex (OpenAI)"
Write-Host " -Cline 仅操作 Cline"
Write-Host " -OpenCode 仅操作 OpenCode"
Write-Host " -Copilot 仅操作 GitHub Copilot (.github\copilot-instructions.md)"
Write-Host " -Trae 仅操作 Trae (.trae\rules)"
Write-Host " -OpenClaw 仅操作 OpenClaw (~\.openclaw\skills)"
Write-Host " -Hermes 仅操作 Hermes (~\.hermes\skills + HERMES.md)"
Write-Host ""
Write-Host "示例:"
Write-Host " install.bat # 全部工具"
Write-Host " install.bat ascend-kg # 仅 ascend-kg"
Write-Host " install.bat ascend-kg -Claude # ascend-kg x Claude Code"
Write-Host " install.bat ascend-kg -Uninstall # 卸载 ascend-kg"
Write-Host " install.bat -Update # 更新全部工具"
return
}
if ($Update) { $Force = $true }
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$SkillsDir = Join-Path $ScriptDir "skills"
$HomeDir = $env:HOME
if (-not $HomeDir) { $HomeDir = $env:USERPROFILE }
$PortableBase = Join-Path $HomeDir ".kg-tools\skills"
$skills = @()
if ($Skill) {
$skills += $Skill
} else {
if (Test-Path $SkillsDir) {
Get-ChildItem $SkillsDir -Directory | ForEach-Object { $skills += $_.Name }
}
}
if ($skills.Count -eq 0) {
Write-Host "skills\ 下没有可安装的工具"
return
}
$target = ""
if ($Claude) { $target = "claude" }
if ($Cursor) { $target = "cursor" }
if ($Codex) { $target = "codex" }
if ($Cline) { $target = "cline" }
if ($OpenCode) { $target = "opencode" }
if ($Copilot) { $target = "copilot" }
if ($Trae) { $target = "trae" }
if ($OpenClaw) { $target = "openclaw" }
if ($Hermes) { $target = "hermes" }
function Copy-SkillDir($pluginDir, $dst) {
if (Test-Path $dst) { Remove-Item -Recurse -Force $dst }
New-Item -ItemType Directory -Force -Path $dst | Out-Null
Copy-Item (Join-Path $pluginDir "SKILL.md") $dst
foreach ($sub in @("evals", "engine", "references", "experience", "scripts")) {
$src = Join-Path $pluginDir $sub
if (Test-Path $src) { Copy-Item -Recurse $src $dst }
}
$tp = Join-Path $pluginDir "test-prompts.json"
if (Test-Path $tp) { Copy-Item $tp $dst }
$repoRoot = Split-Path -Parent (Split-Path -Parent $pluginDir)
[System.IO.File]::WriteAllText((Join-Path $dst ".repo_source"), ($repoRoot -replace '\\', '/'), (New-Object System.Text.UTF8Encoding $false))
}
function Portable-Ptr($name) {
"> 📌 ascend-kg 完整目录已安装到 ``$PortableBase\$name``(下文 ``references/``、``experience/``、``<skill>`` 均指此目录)"
}
function Install-Claude($name, $pluginDir) {
$skillDir = Join-Path $HomeDir ".claude\skills\$name"
$agentsDir = Join-Path $HomeDir ".claude\agents"
$agentSrc = Join-Path $pluginDir "agents\$name-worker.md"
$agentDst = Join-Path $agentsDir "$name-worker.md"
$skillMd = Join-Path $skillDir "SKILL.md"
if ((Test-Path $skillMd) -and -not $Force) {
Write-Host " - Claude Code skill (已存在,跳过)"
return
}
Copy-SkillDir $pluginDir $skillDir
New-Item -ItemType Directory -Force -Path $agentsDir | Out-Null
if (Test-Path $agentSrc) { Copy-Item $agentSrc $agentDst }
Install-ClaudeMemory $pluginDir
Write-Host " + Claude Code -> $skillDir (skill) + $agentDst (agent) + CLAUDE.md 铁律"
}
function Install-ClaudeMemory($pluginDir) {
$claudeMd = Join-Path $HomeDir ".claude\CLAUDE.md"
$block = Join-Path $pluginDir "claude-memory.md"
if (-not (Test-Path $block)) { return }
New-Item -ItemType Directory -Force -Path (Split-Path $claudeMd) | Out-Null
$start = '<!-- ascend-kg:START -->'
$end = '<!-- ascend-kg:END -->'
if (Test-Path $claudeMd) {
$raw = Get-Content $claudeMd -Raw -ErrorAction SilentlyContinue
if ($null -eq $raw -or $raw -eq "") { $raw = "" }
} else { $raw = "" }
if ($raw -ne "") {
$pattern = "(?s)" + [regex]::Escape($start) + ".*?" + [regex]::Escape($end) + "\r?\n?"
$raw = $raw -replace $pattern, ""
if (-not $raw.EndsWith("`n")) { $raw += "`n" }
}
$raw += (Get-Content $block -Raw)
[System.IO.File]::WriteAllText($claudeMd, $raw, (New-Object System.Text.UTF8Encoding $false))
}
function Install-Cursor($skillMd, $name, $pluginDir) {
$dir = ".cursor\rules"
$file = Join-Path $dir "$name.mdc"
$header = "---`nalwaysApply: true`n---`n`n"
if ((Test-Path $file) -and -not $Force) {
Write-Host " - Cursor (已存在,跳过)"
return
}
New-Item -ItemType Directory -Force -Path $dir | Out-Null
Install-Portable $pluginDir $name
$header + (Portable-Ptr $name) + "`n`n" + (Get-Content $skillMd -Raw) | Set-Content $file
Write-Host " + Cursor -> $file (alwaysApply: true) + 便携目录 $PortableBase\$name"
}
function Install-Codex($skillMd, $pluginDir, $name) {
$file = "AGENTS.md"
if ((Test-Path $file) -and -not $Force) {
Write-Host " - Codex (已存在,跳过)"
return
}
Install-Portable $pluginDir $name
(Portable-Ptr $name) + "`n`n" + (Get-Content $skillMd -Raw) | Set-Content $file
Write-Host " + Codex -> $file + 便携目录 $PortableBase\$name"
}
function Install-HermesMemory($pluginDir) {
$hermesMd = "HERMES.md"
$block = Join-Path $pluginDir "hermes-memory.md"
if (-not (Test-Path $block)) { return }
$start = '<!-- ascend-kg:START -->'
$end = '<!-- ascend-kg:END -->'
if (Test-Path $hermesMd) {
$raw = Get-Content $hermesMd -Raw -ErrorAction SilentlyContinue
if ($null -eq $raw -or $raw -eq "") { $raw = "" }
} else { $raw = "" }
if ($raw -ne "") {
$pattern = "(?s)" + [regex]::Escape($start) + ".*?" + [regex]::Escape($end) + "\r?\n?"
$raw = $raw -replace $pattern, ""
if (-not $raw.EndsWith("`n")) { $raw += "`n" }
}
$raw += (Get-Content $block -Raw)
[System.IO.File]::WriteAllText($hermesMd, $raw, (New-Object System.Text.UTF8Encoding $false))
}
function Install-Hermes($pluginDir) {
$skillDir = Join-Path $HomeDir ".hermes\skills\ascend-kg"
$skillMd = Join-Path $skillDir "SKILL.md"
if ((Test-Path $skillMd) -and -not $Force) {
Write-Host " - Hermes skill (已存在,跳过)"
return
}
Copy-SkillDir $pluginDir $skillDir
Install-HermesMemory $pluginDir
Write-Host " + Hermes -> $skillDir (skill) + HERMES.md 触发指针"
}
function Install-Portable($pluginDir, $name) {
$dir = Join-Path $PortableBase $name
$skillMd = Join-Path $dir "SKILL.md"
if ((Test-Path $skillMd) -and -not $Force) { return }
Copy-SkillDir $pluginDir $dir
}
function Install-Cline($skillMd, $pluginDir, $name) {
$file = ".clinerules"
if ((Test-Path $file) -and -not $Force) {
Write-Host " - Cline (已存在,跳过)"
return
}
Install-Portable $pluginDir $name
(Portable-Ptr $name) + "`n`n" | Add-Content $file
Get-Content $skillMd -Raw | Add-Content $file
Write-Host " + Cline -> $file + 便携目录 $PortableBase\$name"
}
function Install-OpenCode($pluginDir, $name) {
$dir = Join-Path $env:USERPROFILE ".config\opencode\skills\$name"
$file = Join-Path $dir "SKILL.md"
if ((Test-Path $file) -and -not $Force) {
Write-Host " - OpenCode (已存在,跳过)"
return
}
Copy-SkillDir $pluginDir $dir
Write-Host " + OpenCode -> $dir (skill 全量)"
}
function Install-OpenClaw($pluginDir, $name) {
$dir = Join-Path $HomeDir ".openclaw\skills\$name"
$file = Join-Path $dir "SKILL.md"
if ((Test-Path $file) -and -not $Force) {
Write-Host " - OpenClaw (已存在,跳过)"
return
}
Copy-SkillDir $pluginDir $dir
Write-Host " + OpenClaw -> $dir (skill 全量)"
}
function Install-Copilot($skillMd, $pluginDir, $name) {
$dir = ".github"
$file = Join-Path $dir "copilot-instructions.md"
if ((Test-Path $file) -and -not $Force) {
Write-Host " - GitHub Copilot (已存在,跳过)"
return
}
New-Item -ItemType Directory -Force -Path $dir | Out-Null
Install-Portable $pluginDir $name
(Portable-Ptr $name) + "`n`n" + (Get-Content $skillMd -Raw) | Set-Content $file
Write-Host " + GitHub Copilot -> $file + 便携目录 $PortableBase\$name"
}
function Install-Trae($skillMd, $name, $pluginDir) {
$dir = ".trae\rules"
$file = Join-Path $dir "$name.md"
$header = "---`nalwaysApply: true`n---`n`n"
if ((Test-Path $file) -and -not $Force) {
Write-Host " - Trae (已存在,跳过)"
return
}
New-Item -ItemType Directory -Force -Path $dir | Out-Null
Install-Portable $pluginDir $name
$header + (Portable-Ptr $name) + "`n`n" + (Get-Content $skillMd -Raw) | Set-Content $file
Write-Host " + Trae -> $file (alwaysApply: true) + 便携目录 $PortableBase\$name"
}
function Uninstall-Claude($name) {
$skillDir = Join-Path $HomeDir ".claude\skills\$name"
$agentDst = Join-Path $HomeDir ".claude\agents\$name-worker.md"
$removed = $false
if (Test-Path $skillDir) {
Remove-Item -Recurse -Force $skillDir
Write-Host " - 已移除 Claude Code skill: $skillDir"
$removed = $true
}
if (Test-Path $agentDst) {
Remove-Item -Force $agentDst
Write-Host " - 已移除 Claude Code agent: $agentDst"
$removed = $true
}
$claudeMd = Join-Path $HomeDir ".claude\CLAUDE.md"
if ((Test-Path $claudeMd) -and ((Get-Content $claudeMd -Raw -ErrorAction SilentlyContinue) -match '<!-- ascend-kg:START -->')) {
$raw = Get-Content $claudeMd -Raw -ErrorAction SilentlyContinue
$start = '<!-- ascend-kg:START -->'; $end = '<!-- ascend-kg:END -->'
$pattern = "(?s)" + [regex]::Escape($start) + ".*?" + [regex]::Escape($end) + "\r?\n?"
$raw = $raw -replace $pattern, ""
[System.IO.File]::WriteAllText($claudeMd, $raw, (New-Object System.Text.UTF8Encoding $false))
Write-Host " - 已移除 Claude CLAUDE.md 铁律块"
$removed = $true
$after = Get-Content $claudeMd -Raw -ErrorAction SilentlyContinue
if ($null -ne $after -and $after -match '^\s*$') { Remove-Item -Force $claudeMd }
}
if (-not $removed) { Write-Host " - Claude Code: 未安装" }
}
function Uninstall-Cursor($name) {
$file = ".cursor\rules\$name.mdc"
if (Test-Path $file) {
Remove-Item -Force $file
Write-Host " - 已移除 Cursor: $file"
} else {
Write-Host " - Cursor: 未安装"
}
}
function Uninstall-Codex {
if (Test-Path "AGENTS.md") {
Write-Host " ! Codex: AGENTS.md 可能含其他工具内容,请手动清理"
} else {
Write-Host " - Codex: 未安装"
}
}
function Uninstall-Hermes {
$skillDir = Join-Path $HomeDir ".hermes\skills\ascend-kg"
$removed = $false
if (Test-Path $skillDir) {
Remove-Item -Recurse -Force $skillDir
Write-Host " - 已移除 Hermes skill: $skillDir"
$removed = $true
}
$hermesMd = "HERMES.md"
if ((Test-Path $hermesMd) -and ((Get-Content $hermesMd -Raw -ErrorAction SilentlyContinue) -match '<!-- ascend-kg:START -->')) {
$raw = Get-Content $hermesMd -Raw -ErrorAction SilentlyContinue
$start = '<!-- ascend-kg:START -->'; $end = '<!-- ascend-kg:END -->'
$pattern = "(?s)" + [regex]::Escape($start) + ".*?" + [regex]::Escape($end) + "\r?\n?"
$raw = $raw -replace $pattern, ""
[System.IO.File]::WriteAllText($hermesMd, $raw, (New-Object System.Text.UTF8Encoding $false))
Write-Host " - 已移除 Hermes HERMES.md 触发指针块"
$removed = $true
$after = Get-Content $hermesMd -Raw -ErrorAction SilentlyContinue
if ($null -ne $after -and $after -match '^\s*$') { Remove-Item -Force $hermesMd }
}
if (-not $removed) { Write-Host " - Hermes: 未安装" }
}
function Uninstall-Cline {
if (Test-Path ".clinerules") {
Write-Host " ! Cline: .clinerules 可能含其他工具内容,请手动清理"
} else {
Write-Host " - Cline: 未安装"
}
}
function Uninstall-OpenCode {
$dir = Join-Path $env:USERPROFILE ".config\opencode\skills\ascend-kg"
if (Test-Path $dir) {
Remove-Item -Force -Recurse $dir
Write-Host " - 已移除 OpenCode: $dir"
} else {
Write-Host " - OpenCode: 未安装"
}
}
function Uninstall-OpenClaw {
$dir = Join-Path $HomeDir ".openclaw\skills\ascend-kg"
if (Test-Path $dir) {
Remove-Item -Force -Recurse $dir
Write-Host " - 已移除 OpenClaw: $dir"
} else {
Write-Host " - OpenClaw: 未安装"
}
}
function Uninstall-Copilot {
$file = ".github\copilot-instructions.md"
if (Test-Path $file) {
Remove-Item -Force $file
Write-Host " - 已移除 GitHub Copilot: $file"
} else {
Write-Host " - GitHub Copilot: 未安装"
}
}
function Uninstall-Trae($name) {
$file = ".trae\rules\$name.md"
if (Test-Path $file) {
Remove-Item -Force $file
Write-Host " - 已移除 Trae: $file"
} else {
Write-Host " - Trae: 未安装"
}
}
function Uninstall-Portable($name) {
$dir = Join-Path $PortableBase $name
if (Test-Path $dir) {
Remove-Item -Force -Recurse $dir
Write-Host " - 已移除便携目录: $dir"
}
}
function Uninstall-OneSkill($name) {
Write-Host ""
Write-Host "--- $name ---"
if ($target -eq "claude") {
Uninstall-Claude $name
} elseif ($target -eq "cursor") {
Uninstall-Cursor $name
} elseif ($target -eq "codex") {
Uninstall-Codex
} elseif ($target -eq "cline") {
Uninstall-Cline
} elseif ($target -eq "opencode") {
Uninstall-OpenCode
} elseif ($target -eq "copilot") {
Uninstall-Copilot
} elseif ($target -eq "trae") {
Uninstall-Trae $name
} elseif ($target -eq "openclaw") {
Uninstall-OpenClaw
} elseif ($target -eq "hermes") {
Uninstall-Hermes
} else {
Uninstall-Claude $name
Uninstall-Cursor $name
Uninstall-Codex
Uninstall-Cline
Uninstall-OpenCode
Uninstall-Copilot
Uninstall-Trae $name
Uninstall-OpenClaw
Uninstall-Hermes
Uninstall-Portable $name
}
}
function Install-OneSkill($name) {
$plugin = Join-Path $SkillsDir $name
$skillMd = Join-Path $plugin "SKILL.md"
if (-not (Test-Path $skillMd)) {
Write-Host " ! $name : 找不到 $skillMd,跳过"
return
}
Write-Host ""
Write-Host "--- $name ---"
if ($target -eq "claude") {
Install-Claude $name $plugin
} elseif ($target -eq "cursor") {
Install-Cursor $skillMd $name $plugin
} elseif ($target -eq "codex") {
Install-Codex $skillMd $plugin $name
} elseif ($target -eq "cline") {
Install-Cline $skillMd $plugin $name
} elseif ($target -eq "opencode") {
Install-OpenCode $plugin $name
} elseif ($target -eq "copilot") {
Install-Copilot $skillMd $plugin $name
} elseif ($target -eq "trae") {
Install-Trae $skillMd $name $plugin
} elseif ($target -eq "openclaw") {
Install-OpenClaw $plugin $name
} elseif ($target -eq "hermes") {
Install-Hermes $plugin
} else {
if (Test-Path (Join-Path $HomeDir ".claude")) {
Install-Claude $name $plugin
} else {
Write-Host " - Claude Code (未检测到)"
}
if (Test-Path ".cursor") {
Install-Cursor $skillMd $name $plugin
} else {
Write-Host " - Cursor (未检测到)"
}
if ((Test-Path "AGENTS.md") -or (Test-Path ".codex")) {
Install-Codex $skillMd $plugin $name
} else {
Write-Host " - Codex (未检测到)"
}
if (Test-Path ".clinerules") {
Install-Cline $skillMd $plugin $name
} else {
Write-Host " - Cline (未检测到)"
}
if (Test-Path (Join-Path $env:USERPROFILE ".config\opencode")) {
Install-OpenCode $plugin $name
} else {
Write-Host " - OpenCode (未检测到)"
}
if (Test-Path (Join-Path $HomeDir ".openclaw")) {
Install-OpenClaw $plugin $name
} else {
Write-Host " - OpenClaw (未检测到)"
}
if (Test-Path ".trae") {
Install-Trae $skillMd $name $plugin
} else {
Write-Host " - Trae (未检测到)"
}
if (Test-Path (Join-Path $HomeDir ".hermes")) {
Install-Hermes $plugin
} else {
Write-Host " - Hermes (未检测到)"
}
}
}
if ($Update) {
Write-Host ""
Write-Host "正在更新 kg-tools..."
$gitDir = Join-Path $ScriptDir ".git"
if (Test-Path $gitDir) {
$headBefore = git -C $ScriptDir rev-parse HEAD 2>$null
git -C $ScriptDir pull 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "已拉取最新代码"
$headAfter = git -C $ScriptDir rev-parse HEAD 2>$null
if ($headBefore -and ($headBefore -ne $headAfter)) {
Write-Host "⚠️ 代码已更新:本次可能仍用旧安装逻辑,请再执行一次 install.bat -Update 完成升级"
}
} else {
Write-Host "git pull 失败,将使用本地文件重装"
}
} else {
Write-Host "非 git 仓库,将使用本地文件重装"
}
}
if ($Uninstall) {
Write-Host "目标工具: $($skills -join ', ')"
foreach ($s in $skills) { Uninstall-OneSkill $s }
Write-Host ""
Write-Host "卸载完成。Claude Code 需重启或 /reload-plugins。"
return
}
Write-Host "目标工具: $($skills -join ', ')"
foreach ($s in $skills) { Install-OneSkill $s }
Write-Host ""
Write-Host "安装完成。"
Write-Host "- Claude Code 需重启或 /reload-plugins(让 /agents 发现 ascend-kg-worker)"
Write-Host "- Cursor / Trae / Cline / Codex / Hermes / OpenCode / OpenClaw / Copilot 下次启动自动生效"
Write-Host '- 设置 API Key: $env:ASCEND_KG_API_KEY="你的Key"'
Write-Host " 免费申请: https://ascend.wiki/register"