Release wordcraft-mcp and gridcraft-mcp 0.3.0: client-neutral skills, Cursor plugins.
This commit is contained in:
1 parent
debdf92877
commit
4c7e3ff720
26 files changed
+1008
-236
No files matched your search
@@ -0,0 +1,197 @@
|
||||
# Builds dist\cursor\ from skills\: flat skill copies, mcp snippets, one plugin per skill.
|
||||
# Usage: scripts\build-cursor.ps1 [-Name <skill-name>]
|
||||
param([string]$Name)
|
||||
. (Join-Path $PSScriptRoot 'lib.ps1')
|
||||
. (Join-Path $PSScriptRoot 'cursor-deeplink.ps1')
|
||||
|
||||
$CursorDist = Join-Path $DistDir 'cursor'
|
||||
$ServerKeys = @{
|
||||
'wordcraft-mcp' = 'wordcraft'
|
||||
'gridcraft-mcp' = 'gridcraft'
|
||||
}
|
||||
|
||||
function Get-McpServerKey([string]$SkillName) {
|
||||
if ($ServerKeys.ContainsKey($SkillName)) { return $ServerKeys[$SkillName] }
|
||||
# fallback: strip trailing -mcp
|
||||
if ($SkillName -match '^(.+)-mcp$') { return $Matches[1] }
|
||||
return $SkillName
|
||||
}
|
||||
|
||||
function Convert-ClaudeArgsToCursor([object[]]$CliArgs) {
|
||||
$out = New-Object System.Collections.Generic.List[string]
|
||||
foreach ($a in $CliArgs) {
|
||||
$s = [string]$a
|
||||
if ($s -eq '${user_config.author}') { $out.Add('${AUTHOR}'); continue }
|
||||
if ($s -eq '${user_config.read_root}') { $out.Add('${READ_ROOT}'); continue }
|
||||
if ($s -eq '${user_config.write_root}') { $out.Add('${WRITE_ROOT}'); continue }
|
||||
$out.Add($s)
|
||||
}
|
||||
return , $out.ToArray()
|
||||
}
|
||||
|
||||
function Convert-ArgsToUserHomeDefaults([object[]]$CliArgs) {
|
||||
$out = New-Object System.Collections.Generic.List[string]
|
||||
foreach ($a in $CliArgs) {
|
||||
$s = [string]$a
|
||||
if ($s -eq '${user_config.author}' -or $s -eq '${AUTHOR}') { $out.Add('Claude'); continue }
|
||||
if ($s -eq '${user_config.read_root}' -or $s -eq '${READ_ROOT}') { $out.Add('${userHome}/Documents'); continue }
|
||||
if ($s -eq '${user_config.write_root}' -or $s -eq '${WRITE_ROOT}') { $out.Add('${userHome}/Documents/Claude'); continue }
|
||||
$out.Add($s)
|
||||
}
|
||||
return , $out.ToArray()
|
||||
}
|
||||
|
||||
function Build-OneSkill([string]$N) {
|
||||
$dir = Join-Path $SkillsDir $N
|
||||
if (-not (Test-Path $dir -PathType Container)) {
|
||||
Write-Host "skills/$N fehlt."
|
||||
return $false
|
||||
}
|
||||
$ver = Get-SkillVersion $dir
|
||||
if (-not $ver) {
|
||||
Write-Host "CHANGELOG von $N hat keine Version."
|
||||
return $false
|
||||
}
|
||||
|
||||
$skillPath = Join-Path $dir 'SKILL.md'
|
||||
$fm = Get-Frontmatter $skillPath
|
||||
if ($null -eq $fm) {
|
||||
Write-Host "${N}: kein Frontmatter."
|
||||
return $false
|
||||
}
|
||||
$fmName = Get-FmValue $fm 'name'
|
||||
$desc = Get-FmValue $fm 'description'
|
||||
if ($fmName -cne $N) {
|
||||
Write-Host "${N}: Frontmatter name '$fmName' != Ordner."
|
||||
return $false
|
||||
}
|
||||
if (-not $desc -or $desc.Length -gt 1024) {
|
||||
Write-Host "${N}: description fehlt oder > 1024."
|
||||
return $false
|
||||
}
|
||||
|
||||
# Flat skill copy
|
||||
$flatDir = Join-Path (Join-Path $CursorDist 'skills') $N
|
||||
New-Item -ItemType Directory -Force -Path $flatDir | Out-Null
|
||||
Copy-Item -LiteralPath $skillPath -Destination (Join-Path $flatDir 'SKILL.md') -Force
|
||||
|
||||
$extManPath = Join-Path $dir 'extension\manifest.json'
|
||||
$hasExt = Test-Path $extManPath
|
||||
$pluginRoot = Join-Path (Join-Path $CursorDist 'plugins') $N
|
||||
if (Test-Path $pluginRoot) { Remove-Item $pluginRoot -Recurse -Force }
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $pluginRoot '.cursor-plugin') | Out-Null
|
||||
$pluginSkillDir = Join-Path (Join-Path $pluginRoot 'skills') $N
|
||||
New-Item -ItemType Directory -Force -Path $pluginSkillDir | Out-Null
|
||||
Copy-Item -LiteralPath $skillPath -Destination (Join-Path $pluginSkillDir 'SKILL.md') -Force
|
||||
|
||||
$displayDesc = $desc
|
||||
$authorName = 'Dominic Gundel'
|
||||
$pluginVars = $null
|
||||
$mcpForPlugin = $null
|
||||
$mcpStandalone = $null
|
||||
$serverKey = Get-McpServerKey $N
|
||||
|
||||
if ($hasExt) {
|
||||
$man = (Read-Text $extManPath) | ConvertFrom-Json
|
||||
if ($man.version -cne $ver) {
|
||||
Write-Host "${N}: manifest version '$($man.version)' != CHANGELOG '$ver'."
|
||||
return $false
|
||||
}
|
||||
$dn = [string]$man.display_name
|
||||
if ($dn -match ' for Claude$') {
|
||||
$displayDesc = ($dn -replace ' for Claude$', ' for Cursor') + '. ' + $desc
|
||||
}
|
||||
elseif ($man.description) {
|
||||
$displayDesc = [string]$man.description
|
||||
}
|
||||
if ($man.author -and $man.author.name) { $authorName = [string]$man.author.name }
|
||||
|
||||
$cmd = [string]$man.server.mcp_config.command
|
||||
$argsRaw = @($man.server.mcp_config.args)
|
||||
$argsPlugin = Convert-ClaudeArgsToCursor $argsRaw
|
||||
$argsHome = Convert-ArgsToUserHomeDefaults $argsRaw
|
||||
|
||||
$transportPlugin = @{ command = $cmd; args = @($argsPlugin) }
|
||||
$transportHome = @{ command = $cmd; args = @($argsHome) }
|
||||
|
||||
$mcpForPlugin = @{ mcpServers = @{ $serverKey = $transportPlugin } }
|
||||
$mcpStandalone = @{ mcpServers = @{ $serverKey = $transportHome } }
|
||||
|
||||
if ($man.user_config) {
|
||||
$props = @{}
|
||||
$required = @()
|
||||
if ($man.user_config.read_root) {
|
||||
$props['READ_ROOT'] = @{
|
||||
type = 'string'
|
||||
title = 'Lese-Ordner'
|
||||
description = 'Weit fassen (Standard: Dokumente).'
|
||||
default = '${userHome}/Documents'
|
||||
}
|
||||
$required += 'READ_ROOT'
|
||||
}
|
||||
if ($man.user_config.write_root) {
|
||||
$props['WRITE_ROOT'] = @{
|
||||
type = 'string'
|
||||
title = 'Schreib-Ordner'
|
||||
description = 'Eng halten (Standard: Dokumente/Claude).'
|
||||
default = '${userHome}/Documents/Claude'
|
||||
}
|
||||
$required += 'WRITE_ROOT'
|
||||
}
|
||||
if ($man.user_config.author) {
|
||||
$props['AUTHOR'] = @{
|
||||
type = 'string'
|
||||
title = 'Autorname'
|
||||
description = 'Name fuer nachverfolgte Aenderungen.'
|
||||
default = 'Claude'
|
||||
}
|
||||
}
|
||||
if ($props.Count -gt 0) {
|
||||
$pluginVars = @{
|
||||
type = 'object'
|
||||
properties = $props
|
||||
}
|
||||
if ($required.Count -gt 0) { $pluginVars['required'] = $required }
|
||||
}
|
||||
}
|
||||
|
||||
$mcpDir = Join-Path $CursorDist 'mcp'
|
||||
New-Item -ItemType Directory -Force -Path $mcpDir | Out-Null
|
||||
$snippetPath = Join-Path $mcpDir "$N.json"
|
||||
Write-Text $snippetPath (($mcpStandalone | ConvertTo-Json -Depth 20) + "`n")
|
||||
}
|
||||
|
||||
$pluginJson = @{
|
||||
name = $N
|
||||
version = $ver
|
||||
description = $displayDesc
|
||||
author = @{ name = $authorName }
|
||||
license = 'MIT'
|
||||
homepage = 'https://git.gundel.dev/dg/claude-skills'
|
||||
repository = 'https://git.gundel.dev/dg/claude-skills.git'
|
||||
}
|
||||
if ($pluginVars) { $pluginJson['variables'] = $pluginVars }
|
||||
|
||||
Write-Text (Join-Path $pluginRoot '.cursor-plugin\plugin.json') (($pluginJson | ConvertTo-Json -Depth 20) + "`n")
|
||||
if ($mcpForPlugin) {
|
||||
Write-Text (Join-Path $pluginRoot 'mcp.json') (($mcpForPlugin | ConvertTo-Json -Depth 20) + "`n")
|
||||
}
|
||||
|
||||
# Validate JSON round-trip
|
||||
$null = (Read-Text (Join-Path $pluginRoot '.cursor-plugin\plugin.json')) | ConvertFrom-Json
|
||||
if ($mcpForPlugin) {
|
||||
$null = (Read-Text (Join-Path $pluginRoot 'mcp.json')) | ConvertFrom-Json
|
||||
}
|
||||
|
||||
Write-Host "OK cursor plugin $N $ver"
|
||||
return $true
|
||||
}
|
||||
|
||||
if ($Name) { $names = @($Name) } else { $names = @(Get-SkillNames) }
|
||||
New-Item -ItemType Directory -Force -Path $CursorDist | Out-Null
|
||||
$ok = $true
|
||||
foreach ($n in $names) {
|
||||
if (-not (Build-OneSkill $n)) { $ok = $false }
|
||||
}
|
||||
if (-not $ok) { exit 1 }
|
||||
exit 0
|
||||
Reference in new issue
Block a user