Publish Next.js Agent Skills

Constraint: Upstream next-skills is a multi-skill collection under skills/*/SKILL.md.\nRejected: Copy upstream README badge/install docs | marketplace README stays install-focused and plugin content avoids nonessential images.\nConfidence: high\nScope-risk: moderate\nDirective: Use skill-collection with skillsPath for repositories organized as direct child skill directories.\nTested: python scripts/validate_marketplace.py; python /Users/eapil/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py plugins/codex/plugins/next-skills; temp CODEX_HOME codex plugin marketplace add/list/add plus debug prompt-input.\nNot-tested: scripts/sync_external_plugins.ps1 execution because pwsh/powershell is not installed.
This commit is contained in:
KeyInfo Bot
2026-06-15 16:30:27 +08:00
parent 5603269374
commit 104a4b101d
29 changed files with 4104 additions and 0 deletions
+114
View File
@@ -702,6 +702,117 @@ function Sync-ClaudeSkill {
Write-Provenance -PluginDir $pluginDir -Source $Source -Commit $Commit -SyncedAt $SyncedAt -SourcePath $Source.skillPath
}
function Sync-SkillCollection {
param(
[object]$Source,
[string]$ClonePath,
[string]$Commit,
[string]$PluginsRoot,
[string]$RepoRoot,
[string]$SyncedAt
)
$skillsPath = "skills"
if ($Source.PSObject.Properties.Name -contains "skillsPath" -and $Source.skillsPath) {
$skillsPath = $Source.skillsPath
} elseif ($Source.PSObject.Properties.Name -contains "skillPath" -and $Source.skillPath) {
$skillsPath = $Source.skillPath
}
if ($skillsPath -eq ".") {
$sourceSkillsRoot = $ClonePath
} else {
$sourceSkillsRoot = Join-Path $ClonePath $skillsPath
}
if (-not (Test-Path -LiteralPath $sourceSkillsRoot)) {
throw "skill-collection adapter requires a skills directory: $sourceSkillsRoot"
}
$skillDirs = @(Get-ChildItem -LiteralPath $sourceSkillsRoot -Directory | Where-Object {
Test-Path -LiteralPath (Join-Path $_.FullName "SKILL.md")
} | Sort-Object Name)
if ($skillDirs.Count -eq 0) {
throw "skill-collection adapter found no child SKILL.md files: $sourceSkillsRoot"
}
$pluginName = $Source.pluginName
$pluginDir = Join-Path $PluginsRoot $pluginName
Remove-PathIfExists -Path $pluginDir -Within $RepoRoot
New-Item -ItemType Directory -Force -Path (Join-Path $pluginDir ".codex-plugin") | Out-Null
$skillsRoot = Join-Path $pluginDir "skills"
New-Item -ItemType Directory -Force -Path $skillsRoot | Out-Null
foreach ($skillDir in $skillDirs) {
Copy-DirectoryFiltered -Source $skillDir.FullName -Destination (Join-Path $skillsRoot $skillDir.Name) -Within $RepoRoot
}
$includeRootFiles = @()
if ($Source.PSObject.Properties.Name -contains "includeRootFiles" -and $Source.includeRootFiles) {
$includeRootFiles = @($Source.includeRootFiles)
}
foreach ($rootFile in $includeRootFiles) {
Copy-PathIfExists -Source (Join-Path $ClonePath $rootFile) -Destination (Join-Path $pluginDir $rootFile) -Within $RepoRoot
}
Remove-ConfiguredExcludes -Root $pluginDir -ExcludePaths $Source.excludePaths -Within $RepoRoot
Remove-ReadmeImageReferences -Root $pluginDir -ImagePathPrefixes $Source.readmeImageExcludes
Remove-ReadmeLines -Root $pluginDir -LineExcludes $Source.readmeLineExcludes
Compress-ImagesToWebp -Root $pluginDir -CompressPaths $Source.webpCompressPaths
$metadata = @{}
if ($Source.PSObject.Properties.Name -contains "metadata" -and $Source.metadata) {
$metadata = ConvertTo-Hashtable $Source.metadata
}
$description = $metadata.description
if (-not $description) {
$description = "$pluginName skill collection imported from $($Source.repo)."
}
$displayName = $metadata.displayName
if (-not $displayName) {
$displayName = $pluginName
}
$version = $metadata.version
if (-not $version) {
$version = "0.1.0"
}
$homepage = $metadata.homepage
if (-not $homepage) {
$homepage = $Source.repo -replace "\.git$", ""
}
$repository = $metadata.repository
if (-not $repository) {
$repository = $Source.repo -replace "\.git$", ""
}
$license = $metadata.license
if (-not $license) {
$license = "UNKNOWN"
}
$manifest = [ordered]@{
name = $pluginName
version = $version
description = $description
author = New-AuthorObject $metadata.author
homepage = $homepage
repository = $repository
license = $license
keywords = @($metadata.keywords)
skills = "./skills/"
interface = [ordered]@{
displayName = $displayName
shortDescription = $description
longDescription = $description
developerName = (New-AuthorObject $metadata.author).name
category = (Get-SourceCategory $Source)
capabilities = @("Read", "Write")
defaultPrompt = @("Use $displayName for this task.")
websiteURL = $homepage
privacyPolicyURL = $repository
termsOfServiceURL = $repository
brandColor = $(if ($Source.PSObject.Properties.Name -contains "brandColor" -and $Source.brandColor) { $Source.brandColor } else { "#2563EB" })
screenshots = @()
}
}
Write-JsonFile -Path (Join-Path $pluginDir ".codex-plugin\plugin.json") -Value $manifest
Apply-LocalOverrides -PluginDir $pluginDir -Source $Source
Write-Provenance -PluginDir $pluginDir -Source $Source -Commit $Commit -SyncedAt $SyncedAt -SourcePath $skillsPath
}
function Update-Marketplace {
param(
[string]$MarketplacePath,
@@ -779,6 +890,9 @@ foreach ($source in $sources) {
"claude-skill" {
Sync-ClaudeSkill -Source $source -ClonePath $clone.path -Commit $clone.commit -PluginsRoot $pluginsRoot -RepoRoot $repoRoot -SyncedAt $sourceSyncedAt
}
"skill-collection" {
Sync-SkillCollection -Source $source -ClonePath $clone.path -Commit $clone.commit -PluginsRoot $pluginsRoot -RepoRoot $repoRoot -SyncedAt $sourceSyncedAt
}
default {
throw "Unknown adapter '$($source.adapter)' for $($source.id)."
}