diff --git a/README.md b/README.md index d5e7906d5..efc5cc2a2 100644 --- a/README.md +++ b/README.md @@ -46,14 +46,18 @@ Browse the agents below and copy/adapt the ones you need! ### Option 3: Use with Other Tools (Cursor, Aider, Windsurf, Gemini CLI, OpenCode) +#### Linux / macOS (Bash) ```bash -# Step 1 -- generate integration files for all supported tools +# Step 1 -- generate integration files ./scripts/convert.sh -# Step 2 -- install interactively (auto-detects what you have installed) +# Step 2 -- install interactively ./scripts/install.sh +``` + +* Or target a specific tool directly -# Or target a specific tool directly +```bash ./scripts/install.sh --tool cursor ./scripts/install.sh --tool copilot ./scripts/install.sh --tool aider @@ -62,6 +66,26 @@ Browse the agents below and copy/adapt the ones you need! See the [Multi-Tool Integrations](#-multi-tool-integrations) section below for full details. +#### Windows (PowerShell) +```powershell +# Step 1 -- generate integration files +.\scripts\convert.ps1 + +# Step 2 -- install interactively +.\scripts\install.ps1 +``` + +* Or target a specific tool directly + +```powershell +.\scripts\install.ps1 -Tool cursor +.\scripts\install.ps1 -Tool copilot +.\scripts\install.ps1 -Tool aider +.\scripts\install.ps1 -Tool windsurf +``` + +See the [Multi-Tool Integrations](#-multi-tool-integrations) section below for full details. + --- ## 🎨 The Agency Roster @@ -501,16 +525,24 @@ The Agency works natively with Claude Code, and ships conversion + install scrip ### ⚡ Quick Install -**Step 1 -- Generate integration files:** +#### Linux / macOS (Bash) ```bash +# Step 1 -- generate integration files ./scripts/convert.sh -``` -**Step 2 -- Install (interactive, auto-detects your tools):** -```bash +# Step 2 -- install interactively ./scripts/install.sh ``` +#### Windows (PowerShell) +```powershell +# Step 1 -- generate integration files +.\scripts\convert.ps1 + +# Step 2 -- install interactively +.\scripts\install.ps1 +``` + The installer scans your system for installed tools, shows a checkbox UI, and lets you pick exactly what to install: ``` @@ -536,6 +568,8 @@ The installer scans your system for installed tools, shows a checkbox UI, and le ``` **Or install a specific tool directly:** + +#### Linux / macOS (Bash) ```bash ./scripts/install.sh --tool cursor ./scripts/install.sh --tool opencode @@ -543,11 +577,26 @@ The installer scans your system for installed tools, shows a checkbox UI, and le ./scripts/install.sh --tool antigravity ``` +#### Windows (PowerShell) +```powershell +.\scripts\install.ps1 -Tool cursor +.\scripts\install.ps1 -Tool opencode +.\scripts\install.ps1 -Tool openclaw +.\scripts\install.ps1 -Tool antigravity +``` + **Non-interactive (CI/scripts):** + +#### Linux / macOS (Bash) ```bash ./scripts/install.sh --no-interactive --tool all ``` +#### Windows (PowerShell) +```powershell +.\scripts\install.ps1 -NoInteractive -Tool all +``` + --- ### Tool-Specific Instructions @@ -557,10 +606,16 @@ The installer scans your system for installed tools, shows a checkbox UI, and le Agents are copied directly from the repo into `~/.claude/agents/` -- no conversion needed. +#### Linux / macOS (Bash) ```bash ./scripts/install.sh --tool claude-code ``` +#### Windows (PowerShell) +```powershell +.\scripts\install.ps1 -Tool claude-code +``` + Then activate in Claude Code: ``` Use the Frontend Developer agent to review this component. @@ -574,10 +629,16 @@ See [integrations/claude-code/README.md](integrations/claude-code/README.md) for Agents are copied directly from the repo into `~/.github/agents/` and `~/.copilot/agents/` -- no conversion needed. +#### Linux / macOS (Bash) ```bash ./scripts/install.sh --tool copilot ``` +#### Windows (PowerShell) +```powershell +.\scripts\install.ps1 -Tool copilot +``` + Then activate in GitHub Copilot: ``` Use the Frontend Developer agent to review this component. @@ -591,10 +652,16 @@ See [integrations/github-copilot/README.md](integrations/github-copilot/README.m Each agent becomes a skill in `~/.gemini/antigravity/skills/agency-/`. +#### Linux / macOS (Bash) ```bash ./scripts/install.sh --tool antigravity ``` +#### Windows (PowerShell) +```powershell +.\scripts\install.ps1 -Tool antigravity +``` + Activate in Gemini with Antigravity: ``` @agency-frontend-developer review this React component @@ -609,11 +676,18 @@ See [integrations/antigravity/README.md](integrations/antigravity/README.md) for Installs as a Gemini CLI extension with one skill per agent plus a manifest. On a fresh clone, generate the Gemini extension files before running the installer. +#### Linux / macOS (Bash) ```bash ./scripts/convert.sh --tool gemini-cli ./scripts/install.sh --tool gemini-cli ``` +#### Windows (PowerShell) +```powershell +.\scripts\convert.ps1 -Tool gemini-cli +.\scripts\install.ps1 -Tool gemini-cli +``` + See [integrations/gemini-cli/README.md](integrations/gemini-cli/README.md) for details. @@ -622,11 +696,18 @@ See [integrations/gemini-cli/README.md](integrations/gemini-cli/README.md) for d Agents are placed in `.opencode/agents/` in your project root (project-scoped). +#### Linux / macOS (Bash) ```bash cd /your/project /path/to/agency-agents/scripts/install.sh --tool opencode ``` +#### Windows (PowerShell) +```powershell +Set-Location "C:\your\project" +& "D:\path\to\agency-agents\scripts\install.ps1" -Tool opencode +``` + Or install globally: ```bash mkdir -p ~/.config/opencode/agents @@ -646,11 +727,18 @@ See [integrations/opencode/README.md](integrations/opencode/README.md) for detai Each agent becomes a `.mdc` rule file in `.cursor/rules/` of your project. +#### Linux / macOS (Bash) ```bash cd /your/project /path/to/agency-agents/scripts/install.sh --tool cursor ``` +#### Windows (PowerShell) +```powershell +Set-Location "C:\your\project" +& "D:\path\to\agency-agents\scripts\install.ps1" -Tool cursor +``` + Rules are auto-applied when Cursor detects them in the project. Reference them explicitly: ``` Use the @security-engineer rules to review this code. @@ -664,11 +752,18 @@ See [integrations/cursor/README.md](integrations/cursor/README.md) for details. All agents are compiled into a single `CONVENTIONS.md` file that Aider reads automatically. +#### Linux / macOS (Bash) ```bash cd /your/project /path/to/agency-agents/scripts/install.sh --tool aider ``` +#### Windows (PowerShell) +```powershell +Set-Location "C:\your\project" +& "D:\path\to\agency-agents\scripts\install.ps1" -Tool aider +``` + Then reference agents in your Aider session: ``` Use the Frontend Developer agent to refactor this component. @@ -682,11 +777,18 @@ See [integrations/aider/README.md](integrations/aider/README.md) for details. All agents are compiled into `.windsurfrules` in your project root. +#### Linux / macOS (Bash) ```bash cd /your/project /path/to/agency-agents/scripts/install.sh --tool windsurf ``` +#### Windows (PowerShell) +```powershell +Set-Location "C:\your\project" +& "D:\path\to\agency-agents\scripts\install.ps1" -Tool windsurf +``` + Reference agents in Windsurf's Cascade: ``` Use the Reality Checker agent to verify this is production ready. @@ -700,10 +802,16 @@ See [integrations/windsurf/README.md](integrations/windsurf/README.md) for detai Each agent becomes a workspace with `SOUL.md`, `AGENTS.md`, and `IDENTITY.md` in `~/.openclaw/agency-agents/`. +#### Linux / macOS (Bash) ```bash ./scripts/install.sh --tool openclaw ``` +#### Windows (PowerShell) +```powershell +.\scripts\install.ps1 -Tool openclaw +``` + Agents are registered and available by `agentId` in OpenClaw sessions. See [integrations/openclaw/README.md](integrations/openclaw/README.md) for details. @@ -715,6 +823,7 @@ See [integrations/openclaw/README.md](integrations/openclaw/README.md) for detai SubAgents are installed to `.qwen/agents/` in your project root (project-scoped). +#### Linux / macOS (Bash) ```bash # Convert and install (run from your project root) cd /your/project @@ -722,6 +831,13 @@ cd /your/project ./scripts/install.sh --tool qwen ``` +#### Windows (PowerShell) +```powershell +Set-Location "C:\your\project" +& "D:\path\to\agency-agents\scripts\convert.ps1" -Tool qwen +& "D:\path\to\agency-agents\scripts\install.ps1" -Tool qwen +``` + **Usage in Qwen Code:** - Reference by name: `Use the frontend-developer agent to review this component` - Or let Qwen auto-delegate based on task context @@ -737,9 +853,16 @@ cd /your/project When you add new agents or edit existing ones, regenerate all integration files: +#### Linux / macOS (Bash) ```bash -./scripts/convert.sh # regenerate all -./scripts/convert.sh --tool cursor # regenerate just one tool +./scripts/convert.sh # regenerate all +./scripts/convert.sh --tool cursor # regenerate just one tool +``` + +#### Windows (PowerShell) +```powershell +.\scripts\convert.ps1 # regenerate all +.\scripts\convert.ps1 -Tool cursor # regenerate just one tool ``` --- diff --git a/scripts/convert.ps1 b/scripts/convert.ps1 new file mode 100644 index 000000000..a3164bef3 --- /dev/null +++ b/scripts/convert.ps1 @@ -0,0 +1,341 @@ +# convert.ps1 — Convert agency agent .md files into tool-specific formats. +# +# Reads all agent files from the standard category directories and outputs +# converted files to integrations//. Run this to regenerate all +# integration files after adding or modifying agents. +# +# Usage: +# .\scripts\convert.ps1 [-Tool ] [-Out ] [-Help] + +param ( + [string]$Tool = "all", + [string]$Out, + [switch]$Help +) + +if ($Help) { + Write-Host "Usage: .\scripts\convert.ps1 [-Tool ] [-Out ] [-Help]" + Write-Host "" + Write-Host "Tools: antigravity, gemini-cli, opencode, cursor, aider, windsurf, openclaw, qwen, all (default)" + exit 0 +} + +$RepoRoot = Resolve-Path "$PSScriptRoot\.." +if (-not $Out) { + $OutDir = Join-Path $RepoRoot "integrations" +} else { + $OutDir = Resolve-Path $Out +} + +$Today = Get-Date -Format "yyyy-MM-dd" + +$AgentDirs = @( + "design", "engineering", "game-development", "marketing", "paid-media", "sales", "product", "project-management", + "testing", "support", "spatial-computing", "specialized" +) + +# --- Helpers --- + +function Get-Field { + param([string]$Field, [string]$Content) + if ($Content -match "(?ms)^---`r?`n(.*?)^---") { + $Frontmatter = $Matches[1] + if ($Frontmatter -match "(?m)^$($Field):\s*(.*)") { + return $Matches[1].Trim() + } + } + return $null +} + +function Get-Body { + param([string]$Content) + $Parts = $Content -split "(?m)^---`r?`n" + if ($Parts.Length -ge 3) { + return ($Parts[2..($Parts.Length-1)] -join "---`r`n").Trim() + } + return $null +} + +function Slugify { + param([string]$Name) + $S = $Name.ToLower() + $S = $S -replace '[^a-z0-9]', '-' + $S = $S -replace '-+', '-' + return $S.Trim('-') +} + +function Resolve-OpenCode-Color { + param([string]$C) + $C = $C.Trim().ToLower() + $Map = @{ + "cyan" = "#00FFFF" + "blue" = "#3498DB" + "green" = "#2ECC71" + "red" = "#E74C3C" + "purple" = "#9B59B6" + "orange" = "#F39C12" + "teal" = "#008080" + "indigo" = "#6366F1" + "pink" = "#E84393" + "gold" = "#EAB308" + "amber" = "#F59E0B" + "neon-green" = "#10B981" + "neon-cyan" = "#06B6D4" + "metallic-blue" = "#3B82F6" + "yellow" = "#EAB308" + "violet" = "#8B5CF6" + "rose" = "#F43F5E" + "lime" = "#84CC16" + "gray" = "#6B7280" + "fuchsia" = "#D946EF" + } + if ($Map.ContainsKey($C)) { return $Map[$C] } + if ($C -match "^#?[0-9a-f]{6}$") { + if (-not $C.StartsWith("#")) { return "#" + $C.ToUpper() } + return $C.ToUpper() + } + return "#6B7280" +} + +# --- Converters --- + +function Convert-Antigravity { + param($File, $Content) + $Name = Get-Field "name" $Content + $Description = Get-Field "description" $Content + $Slug = "agency-" + (Slugify $Name) + $Body = Get-Body $Content + + $TargetDir = Join-Path $OutDir "antigravity\$Slug" + if (-not (Test-Path $TargetDir)) { New-Item -ItemType Directory -Path $TargetDir -Force } + + $OutFile = Join-Path $TargetDir "SKILL.md" + $Header = @" +--- +name: $Slug +description: $Description +risk: low +source: community +date_added: '$Today' +--- +"@ + $FullContent = $Header + "`r`n" + $Body + [System.IO.File]::WriteAllText($OutFile, $FullContent, (New-Object System.Text.UTF8Encoding $false)) +} + +function Convert-GeminiCLI { + param($File, $Content) + $Name = Get-Field "name" $Content + $Description = Get-Field "description" $Content + $Slug = Slugify $Name + $Body = Get-Body $Content + + $TargetDir = Join-Path $OutDir "gemini-cli\skills\$Slug" + if (-not (Test-Path $TargetDir)) { New-Item -ItemType Directory -Path $TargetDir -Force } + + $OutFile = Join-Path $TargetDir "SKILL.md" + $Header = @" +--- +name: $Slug +description: $Description +--- +"@ + $FullContent = $Header + "`r`n" + $Body + [System.IO.File]::WriteAllText($OutFile, $FullContent, (New-Object System.Text.UTF8Encoding $false)) +} + +function Convert-OpenCode { + param($File, $Content) + $Name = Get-Field "name" $Content + $Description = Get-Field "description" $Content + $Color = Resolve-OpenCode-Color (Get-Field "color" $Content) + $Slug = Slugify $Name + $Body = Get-Body $Content + + $TargetDir = Join-Path $OutDir "opencode\agents" + if (-not (Test-Path $TargetDir)) { New-Item -ItemType Directory -Path $TargetDir -Force } + + $OutFile = Join-Path $TargetDir "$Slug.md" + $Header = @" +--- +name: $Name +description: $Description +mode: subagent +color: '$Color' +--- +"@ + $FullContent = $Header + "`r`n" + $Body + [System.IO.File]::WriteAllText($OutFile, $FullContent, (New-Object System.Text.UTF8Encoding $false)) +} + +function Convert-Cursor { + param($File, $Content) + $Name = Get-Field "name" $Content + $Description = Get-Field "description" $Content + $Slug = Slugify $Name + $Body = Get-Body $Content + + $TargetDir = Join-Path $OutDir "cursor\rules" + if (-not (Test-Path $TargetDir)) { New-Item -ItemType Directory -Path $TargetDir -Force } + + $OutFile = Join-Path $TargetDir "$Slug.mdc" + $Header = @" +--- +description: $Description +globs: "" +alwaysApply: false +--- +"@ + $FullContent = $Header + "`r`n" + $Body + [System.IO.File]::WriteAllText($OutFile, $FullContent, (New-Object System.Text.UTF8Encoding $false)) +} + +function Convert-OpenClaw { + param($File, $Content) + $Name = Get-Field "name" $Content + $Description = Get-Field "description" $Content + $Slug = Slugify $Name + $Body = Get-Body $Content + + $TargetDir = Join-Path $OutDir "openclaw\$Slug" + if (-not (Test-Path $TargetDir)) { New-Item -ItemType Directory -Path $TargetDir -Force } + + $SoulContent = "" + $AgentsContent = "" + $CurrentTarget = "agents" + + $Lines = $Body -split "`r?`n" + foreach ($Line in $Lines) { + if ($Line -match "^##\s") { + $H = $Line.ToLower() + if ($H -match "identity" -or $H -match "communication" -or $H -match "style" -or $H -match "critical rule" -or $H -match "rules you must follow") { + $CurrentTarget = "soul" + } else { + $CurrentTarget = "agents" + } + } + if ($CurrentTarget -eq "soul") { $SoulContent += $Line + "`r`n" } + else { $AgentsContent += $Line + "`r`n" } + } + + [System.IO.File]::WriteAllText((Join-Path $TargetDir "SOUL.md"), $SoulContent, (New-Object System.Text.UTF8Encoding $false)) + [System.IO.File]::WriteAllText((Join-Path $TargetDir "AGENTS.md"), $AgentsContent, (New-Object System.Text.UTF8Encoding $false)) + + $Emoji = Get-Field "emoji" $Content + $Vibe = Get-Field "vibe" $Content + + if ($Emoji -and $Vibe) { + [System.IO.File]::WriteAllText((Join-Path $TargetDir "IDENTITY.md"), "# $Emoji $Name`r`n$Vibe", (New-Object System.Text.UTF8Encoding $false)) + } else { + [System.IO.File]::WriteAllText((Join-Path $TargetDir "IDENTITY.md"), "# $Name`r`n$Description", (New-Object System.Text.UTF8Encoding $false)) + } +} + +function Convert-Qwen { + param($File, $Content) + $Name = Get-Field "name" $Content + $Description = Get-Field "description" $Content + $Tools = Get-Field "tools" $Content + $Slug = Slugify $Name + $Body = Get-Body $Content + + $TargetDir = Join-Path $OutDir "qwen\agents" + if (-not (Test-Path $TargetDir)) { New-Item -ItemType Directory -Path $TargetDir -Force } + + $OutFile = Join-Path $TargetDir "$Slug.md" + if ($Tools) { + $Header = @" +--- +name: $Slug +description: $Description +tools: $Tools +--- +"@ + } else { + $Header = @" +--- +name: $Slug +description: $Description +--- +"@ + } + $FullContent = $Header + "`r`n" + $Body + [System.IO.File]::WriteAllText($OutFile, $FullContent, (New-Object System.Text.UTF8Encoding $false)) +} + +# --- Main --- + +Write-Host "`nThe Agency -- Converting agents to tool-specific formats (PowerShell)" +Write-Host " Repo: $RepoRoot" +Write-Host " Output: $OutDir" +Write-Host " Tool: $Tool" +Write-Host " Date: $Today" + +$AiderHeader = "# The Agency - AI Agent Conventions`r`n#`r`n# Generated by scripts/convert.ps1 - do not edit manually.`r`n`r`n" +$AiderContent = $AiderHeader +$WindsurfHeader = "# The Agency - AI Agent Rules for Windsurf`r`n#`r`n# Generated by scripts/convert.ps1 - do not edit manually.`r`n`r`n" +$WindsurfContent = $WindsurfHeader + +$Total = 0 +$ToolsToRun = if ($Tool -eq "all") { @("antigravity", "gemini-cli", "opencode", "cursor", "aider", "windsurf", "openclaw", "qwen") } else { @($Tool) } + +foreach ($T in $ToolsToRun) { + Write-Host "`nConverting: $T" + $Count = 0 + foreach ($Dir in $AgentDirs) { + $Path = Join-Path $RepoRoot $Dir + if (-not (Test-Path $Path)) { continue } + + $Files = Get-ChildItem -Path $Path -Filter "*.md" -File + foreach ($F in $Files) { + $Content = Get-Content -Path $F.FullName -Raw -Encoding UTF8 + if (-not $Content.StartsWith("---")) { continue } + + $Name = Get-Field "name" $Content + if (-not $Name) { continue } + + switch ($T) { + "antigravity" { Convert-Antigravity $F $Content } + "gemini-cli" { Convert-GeminiCLI $F $Content } + "opencode" { Convert-OpenCode $F $Content } + "cursor" { Convert-Cursor $F $Content } + "openclaw" { Convert-OpenClaw $F $Content } + "qwen" { Convert-Qwen $F $Content } + "aider" { + $Desc = Get-Field "description" $Content + $Body = Get-Body $Content + $AiderContent += "`r`n---`r`n`r`n## $Name`r`n`r`n> $Desc`r`n`r`n$Body`r`n" + } + "windsurf" { + $Desc = Get-Field "description" $Content + $Body = Get-Body $Content + $WindsurfContent += "`r`n================================================================================`r`n## $Name`r`n$Desc`r`n================================================================================`r`n`r`n$Body`r`n" + } + } + $Count++ + } + } + + if ($T -eq "gemini-cli") { + $ManifestDir = Join-Path $OutDir "gemini-cli" + if (-not (Test-Path $ManifestDir)) { New-Item -ItemType Directory -Path $ManifestDir -Force } + [System.IO.File]::WriteAllText((Join-Path $ManifestDir "gemini-extension.json"), '{"name": "agency-agents", "version": "1.0.0"}', (New-Object System.Text.UTF8Encoding $false)) + } + + if ($T -eq "aider") { + $AiderDir = Join-Path $OutDir "aider" + if (-not (Test-Path $AiderDir)) { New-Item -ItemType Directory -Path $AiderDir -Force } + [System.IO.File]::WriteAllText((Join-Path $AiderDir "CONVENTIONS.md"), $AiderContent, (New-Object System.Text.UTF8Encoding $false)) + } + + if ($T -eq "windsurf") { + $WindsurfDir = Join-Path $OutDir "windsurf" + if (-not (Test-Path $WindsurfDir)) { New-Item -ItemType Directory -Path $WindsurfDir -Force } + [System.IO.File]::WriteAllText((Join-Path $WindsurfDir ".windsurfrules"), $WindsurfContent, (New-Object System.Text.UTF8Encoding $false)) + } + + Write-Host " Converted $Count agents for $T" + $Total += $Count +} + +Write-Host "`nDone. Total conversions: $Total" diff --git a/scripts/install.ps1 b/scripts/install.ps1 new file mode 100644 index 000000000..df62362ba --- /dev/null +++ b/scripts/install.ps1 @@ -0,0 +1,249 @@ +# install.ps1 -- Install The Agency agents into your local agentic tool(s). +# +# Reads converted files from integrations/ and copies them to the appropriate +# config directory for each tool. Run scripts/convert.ps1 first if integrations/ +# is missing or stale. +# +# Usage: +# .\scripts\install.ps1 [-Tool ] [-Interactive] [-NoInteractive] [-Help] + +param ( + [string]$Tool = "all", + [switch]$Interactive, + [switch]$NoInteractive, + [switch]$Help +) + +if ($Help) { + Write-Host "Usage: .\scripts\install.ps1 [-Tool ] [-Interactive] [-NoInteractive] [-Help]" + Write-Host "" + Write-Host "Tools: claude-code, copilot, antigravity, gemini-cli, opencode, openclaw, cursor, aider, windsurf, qwen" + exit 0 +} + +$RepoRoot = Resolve-Path "$PSScriptRoot\.." +$Integrations = Join-Path $RepoRoot "integrations" + +if (-not (Test-Path $Integrations)) { + Write-Error "integrations/ not found. Run .\scripts\convert.ps1 first." + exit 1 +} + +$AllTools = @("claude-code", "copilot", "antigravity", "gemini-cli", "opencode", "openclaw", "cursor", "aider", "windsurf", "qwen") + +# --- Detection --- + +function Test-Detected { + param($T) + $UserHome = $env:USERPROFILE + switch ($T) { + "claude-code" { return Test-Path (Join-Path $UserHome ".claude") } + "copilot" { return (Get-Command "code" -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $UserHome ".github")) -or (Test-Path (Join-Path $UserHome ".copilot")) } + "antigravity" { return Test-Path (Join-Path $UserHome ".gemini\antigravity\skills") } + "gemini-cli" { return (Get-Command "gemini" -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $UserHome ".gemini")) } + "cursor" { return (Get-Command "cursor" -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $UserHome ".cursor")) } + "opencode" { return (Get-Command "opencode" -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $UserHome ".config\opencode")) } + "aider" { return [bool](Get-Command "aider" -ErrorAction SilentlyContinue) } + "openclaw" { return (Get-Command "openclaw" -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $UserHome ".openclaw")) } + "windsurf" { return (Get-Command "windsurf" -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $UserHome ".codeium")) } + "qwen" { return (Get-Command "qwen" -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $UserHome ".qwen")) } + } + return $false +} + +# --- Installers --- + +function Install-ClaudeCode { + $Dest = Join-Path $env:USERPROFILE ".claude\agents" + if (-not (Test-Path $Dest)) { New-Item -ItemType Directory -Path $Dest -Force } + $Count = 0 + $AgentDirs = @("design", "engineering", "game-development", "marketing", "paid-media", "sales", "product", "project-management", "testing", "support", "spatial-computing", "specialized") + foreach ($Dir in $AgentDirs) { + $Path = Join-Path $RepoRoot $Dir + if (Test-Path $Path) { + $Files = Get-ChildItem -Path $Path -Filter "*.md" -File + foreach ($F in $Files) { + if ((Get-Content $F.FullName -TotalCount 1 -Encoding UTF8).StartsWith("---")) { + Copy-Item $F.FullName $Dest -Force + $Count++ + } + } + } + } + Write-Host "[OK] Claude Code: $Count agents -> $Dest" +} + +function Install-Copilot { + $DestGithub = Join-Path $env:USERPROFILE ".github\agents" + $DestCopilot = Join-Path $env:USERPROFILE ".copilot\agents" + if (-not (Test-Path $DestGithub)) { New-Item -ItemType Directory -Path $DestGithub -Force } + if (-not (Test-Path $DestCopilot)) { New-Item -ItemType Directory -Path $DestCopilot -Force } + $Count = 0 + $AgentDirs = @("design", "engineering", "game-development", "marketing", "paid-media", "sales", "product", "project-management", "testing", "support", "spatial-computing", "specialized") + foreach ($Dir in $AgentDirs) { + $Path = Join-Path $RepoRoot $Dir + if (Test-Path $Path) { + $Files = Get-ChildItem -Path $Path -Filter "*.md" -File + foreach ($F in $Files) { + if ((Get-Content $F.FullName -TotalCount 1 -Encoding UTF8).StartsWith("---")) { + Copy-Item $F.FullName $DestGithub -Force + Copy-Item $F.FullName $DestCopilot -Force + $Count++ + } + } + } + } + Write-Host "[OK] Copilot: $Count agents -> $DestGithub" +} + +function Install-Antigravity { + $Src = Join-Path $Integrations "antigravity" + $Dest = Join-Path $env:USERPROFILE ".gemini\antigravity\skills" + if (-not (Test-Path $Src)) { Write-Warning "integrations/antigravity missing."; return } + $Dirs = Get-ChildItem -Path $Src -Directory + foreach ($D in $Dirs) { + $Target = Join-Path $Dest $D.Name + if (-not (Test-Path $Target)) { New-Item -ItemType Directory -Path $Target -Force } + Copy-Item (Join-Path $D.FullName "SKILL.md") $Target -Force + } + Write-Host "[OK] Antigravity: $($Dirs.Count) skills -> $Dest" +} + +function Install-GeminiCLI { + $Src = Join-Path $Integrations "gemini-cli" + $Dest = Join-Path $env:USERPROFILE ".gemini\extensions\agency-agents" + if (-not (Test-Path $Src)) { Write-Warning "integrations/gemini-cli missing."; return } + if (-not (Test-Path $Dest)) { New-Item -ItemType Directory -Path $Dest -Force } + Copy-Item (Join-Path $Src "gemini-extension.json") $Dest -Force + $SkillsSrc = Join-Path $Src "skills" + $SkillsDest = Join-Path $Dest "skills" + if (-not (Test-Path $SkillsDest)) { New-Item -ItemType Directory -Path $SkillsDest -Force } + $Dirs = Get-ChildItem -Path $SkillsSrc -Directory + foreach ($D in $Dirs) { + $Target = Join-Path $SkillsDest $D.Name + if (-not (Test-Path $Target)) { New-Item -ItemType Directory -Path $Target -Force } + Copy-Item (Join-Path $D.FullName "SKILL.md") $Target -Force + } + Write-Host "[OK] Gemini CLI: $($Dirs.Count) skills -> $Dest" +} + +function Install-OpenCode { + $Src = Join-Path $Integrations "opencode\agents" + $Dest = Join-Path $PWD ".opencode\agents" + if (-not (Test-Path $Src)) { Write-Warning "integrations/opencode missing."; return } + if (-not (Test-Path $Dest)) { New-Item -ItemType Directory -Path $Dest -Force } + Copy-Item (Join-Path $Src "*.md") $Dest -Force + Write-Host "[OK] OpenCode: agents -> $Dest" +} + +function Install-Cursor { + $Src = Join-Path $Integrations "cursor\rules" + $Dest = Join-Path $PWD ".cursor\rules" + if (-not (Test-Path $Src)) { Write-Warning "integrations/cursor missing."; return } + if (-not (Test-Path $Dest)) { New-Item -ItemType Directory -Path $Dest -Force } + Copy-Item (Join-Path $Src "*.mdc") $Dest -Force + Write-Host "[OK] Cursor: rules -> $Dest" +} + +function Install-Aider { + $Src = Join-Path $Integrations "aider\CONVENTIONS.md" + $Dest = Join-Path $PWD "CONVENTIONS.md" + if (-not (Test-Path $Src)) { Write-Warning "integrations/aider missing."; return } + Copy-Item $Src $Dest -Force + Write-Host "[OK] Aider: CONVENTIONS.md -> $Dest" +} + +function Install-Windsurf { + $Src = Join-Path $Integrations "windsurf\.windsurfrules" + $Dest = Join-Path $PWD ".windsurfrules" + if (-not (Test-Path $Src)) { Write-Warning "integrations/windsurf missing."; return } + Copy-Item $Src $Dest -Force + Write-Host "[OK] Windsurf: .windsurfrules -> $Dest" +} + +function Install-OpenClaw { + $Src = Join-Path $Integrations "openclaw" + $Dest = Join-Path $env:USERPROFILE ".openclaw\agency-agents" + if (-not (Test-Path $Src)) { Write-Warning "integrations/openclaw missing."; return } + if (-not (Test-Path $Dest)) { New-Item -ItemType Directory -Path $Dest -Force } + $Dirs = Get-ChildItem -Path $Src -Directory + foreach ($D in $Dirs) { + $Target = Join-Path $Dest $D.Name + if (-not (Test-Path $Target)) { New-Item -ItemType Directory -Path $Target -Force } + Copy-Item (Join-Path $D.FullName "*.md") $Target -Force + } + Write-Host "[OK] OpenClaw: $($Dirs.Count) workspaces -> $Dest" +} + +function Install-Qwen { + $Src = Join-Path $Integrations "qwen\agents" + $Dest = Join-Path $PWD ".qwen\agents" + if (-not (Test-Path $Src)) { Write-Warning "integrations/qwen missing."; return } + if (-not (Test-Path $Dest)) { New-Item -ItemType Directory -Path $Dest -Force } + Copy-Item (Join-Path $Src "*.md") $Dest -Force + Write-Host "[OK] Qwen Code: agents -> $Dest" +} + +# --- Main Interaction --- + +$SelectedTools = @() + +if ($Interactive -or (-not $NoInteractive -and $Tool -eq "all")) { + Write-Host "`n The Agency -- Tool Installer (PowerShell)" + Write-Host " ------------------------------------------------" + Write-Host " Detected tools (marked with *):" + + $TempList = @() + for ($i = 0; $i -lt $AllTools.Length; $i++) { + $T = $AllTools[$i] + $Detected = Test-Detected $T + $Mark = if ($Detected) { "*" } else { " " } + Write-Host " $($i + 1)) [$Mark] $T" + $TempList += [PSCustomObject]@{ Id = $i + 1; Name = $T; Detected = $Detected } + } + + Write-Host "`n Enter numbers separated by space (e.g. 1 3 7), 'all', or 'q' to quit." + $Input = Read-Host " >> " + + if ($Input -eq "all") { $SelectedTools = $AllTools } + elseif ($Input -eq "q") { exit 0 } + else { + $Indices = $Input -split "\s+" + foreach ($Idx in $Indices) { + if ($Idx -as [int] -and $Idx -ge 1 -and $Idx -le $AllTools.Length) { + $SelectedTools += $AllTools[$Idx - 1] + } + } + } +} elseif ($Tool -ne "all") { + $SelectedTools = @($Tool) +} else { + # Non-interactive, auto-detect + foreach ($T in $AllTools) { + if (Test-Detected $T) { $SelectedTools += $T } + } +} + +if ($SelectedTools.Count -eq 0) { + Write-Warning "No tools selected or detected. Use -Tool to force install." + exit 0 +} + +Write-Host "`nInstalling tools: $($SelectedTools -join ', ')" + +foreach ($T in $SelectedTools) { + switch ($T) { + "claude-code" { Install-ClaudeCode } + "copilot" { Install-Copilot } + "antigravity" { Install-Antigravity } + "gemini-cli" { Install-GeminiCLI } + "opencode" { Install-OpenCode } + "cursor" { Install-Cursor } + "aider" { Install-Aider } + "windsurf" { Install-Windsurf } + "openclaw" { Install-OpenClaw } + "qwen" { Install-Qwen } + } +} + +Write-Host "`n Done! Installed $($SelectedTools.Count) tool(s).`n" diff --git a/scripts/lint-agents.ps1 b/scripts/lint-agents.ps1 new file mode 100644 index 000000000..a4f211056 --- /dev/null +++ b/scripts/lint-agents.ps1 @@ -0,0 +1,100 @@ +# lint-agents.ps1 -- Validates agent markdown files. +# +# Usage: .\scripts\lint-agents.ps1 [file ...] +# If no files given, scans all agent directories. + +param ( + [string[]]$Files +) + +$AgentDirs = @( + "design", "engineering", "game-development", "marketing", "paid-media", "sales", "product", "project-management", + "testing", "support", "spatial-computing", "specialized" +) + +$RequiredFrontmatter = @("name", "description", "color") +$RecommendedSections = @("Identity", "Core Mission", "Critical Rules") + +$Errors = 0 +$Warnings = 0 + +function Lint-File { + param([string]$FilePath) + $Content = Get-Content $FilePath -Raw + $Lines = $Content -split "`r?`n" + + # 1. Check frontmatter delimiters + if ($Lines[0] -ne "---") { + Write-Host "ERROR $($FilePath): missing frontmatter opening ---" -ForegroundColor Red + $script:Errors++ + return + } + + $FrontmatterEnd = -1 + for ($i = 1; $i -lt $Lines.Length; $i++) { + if ($Lines[$i] -eq "---") { + $FrontmatterEnd = $i + break + } + } + + if ($FrontmatterEnd -eq -1) { + Write-Host "ERROR $($FilePath): unclosed frontmatter" -ForegroundColor Red + $script:Errors++ + return + } + + $Frontmatter = ($Lines[1..($FrontmatterEnd - 1)] -join "`n") + $Body = ($Lines[($FrontmatterEnd + 1)..($Lines.Length - 1)] -join "`n") + + # 2. Check required frontmatter fields + foreach ($Field in $RequiredFrontmatter) { + if ($Frontmatter -notmatch "(?m)^$($Field):") { + Write-Host "ERROR $($FilePath): missing frontmatter field '$($Field)'" -ForegroundColor Red + $script:Errors++ + } + } + + # 3. Check recommended sections (warn only) + foreach ($Section in $RecommendedSections) { + if ($Body -notmatch "(?i)$($Section)") { + Write-Host "WARN $($FilePath): missing recommended section '$($Section)'" -ForegroundColor Yellow + $script:Warnings++ + } + } + + # 4. Check file has meaningful content + $WordCount = ($Body -split "\s+").Length + if ($WordCount -lt 50) { + Write-Host "WARN $($FilePath): body seems very short ($($WordCount) words)" -ForegroundColor Yellow + $script:Warnings++ + } +} + +$RepoRoot = Resolve-Path "$PSScriptRoot\.." + +if (-not $Files) { + $Files = @() + foreach ($Dir in $AgentDirs) { + $Path = Join-Path $RepoRoot $Dir + if (Test-Path $Path) { + $Files += (Get-ChildItem -Path $Path -Filter "*.md" -File -Recurse).FullName + } + } +} + +Write-Host "Linting $($Files.Count) agent files..." + +foreach ($F in $Files) { + Lint-File $F +} + +Write-Host "`nResults: $Errors error(s), $Warnings warning(s) in $($Files.Count) files." + +if ($Errors -gt 0) { + Write-Host "FAILED: fix the errors above before merging." -ForegroundColor Red + exit 1 +} else { + Write-Host "PASSED" -ForegroundColor Green + exit 0 +}