diff --git a/.claude-plugin b/.claude-plugin deleted file mode 120000 index 665797f0..00000000 --- a/.claude-plugin +++ /dev/null @@ -1 +0,0 @@ -.plugin \ No newline at end of file diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 00000000..55dbe082 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,752 @@ +{ + "metadata": { + "description": "Official skills and plugins for OpenHands — the open-source AI software engineer.", + "homepage": "https://github.com/OpenHands/extensions", + "maintainer": "OpenHands" + }, + "name": "openhands-extensions", + "owner": { + "email": "contact@all-hands.dev", + "name": "OpenHands" + }, + "plugins": [ + { + "category": "development", + "description": "Create file-based sub-agents as Markdown files — no Python code required. Guides the user through a structured interview and generates a ready-to-deploy .md agent file following the OpenHands SDK specification.", + "keywords": [ + "agent", + "sub-agent", + "file-based", + "markdown", + "no-code", + "create" + ], + "name": "agent-creator", + "source": "./skills/agent-creator" + }, + { + "category": "productivity", + "description": "Add (import) an OpenHands skill from a GitHub repository into the current workspace.", + "keywords": [ + "skill", + "import", + "github", + "sparse-checkout" + ], + "name": "add-skill", + "source": "./skills/add-skill" + }, + { + "category": "productivity", + "description": "Persist and retrieve repository-specific knowledge using AGENTS.md files. Use when you want to save important information about a codebase (build commands, code style, workflows) for future sessions.", + "keywords": [ + "memory", + "knowledge", + "persistence", + "agents" + ], + "name": "agent-memory", + "source": "./skills/agent-memory" + }, + { + "category": "development", + "description": "Guided workflow for building custom AI agents using the OpenHands Software Agent SDK. Use when you want to create a new agent through an interactive interview process that gathers requirements and generates implementation plans.", + "keywords": [ + "agent", + "sdk", + "builder", + "openhands" + ], + "name": "agent-sdk-builder", + "source": "./skills/agent-sdk-builder" + }, + { + "category": "development", + "description": "Simplifies and refines code across three dimensions - code reuse, code quality, and efficiency - while preserving all functionality. Analyzes recently modified code and provides actionable improvement suggestions.", + "keywords": [ + "simplify", + "refine", + "cleanup", + "code-quality", + "reuse", + "efficiency", + "refactor" + ], + "name": "code-simplifier", + "source": "./skills/code-simplifier" + }, + { + "category": "integration", + "description": "Create and manage OpenHands automations - scheduled tasks that run in sandboxes. Use the prompt preset to create automations from natural language, or manage existing automations.", + "keywords": [ + "automation", + "cron", + "scheduled-task", + "sandbox", + "openhands" + ], + "name": "openhands-automation", + "source": "./skills/openhands-automation" + }, + { + "category": "development", + "description": "Work effectively inside a local Agent Canvas environment, including local agent-server auth, safe workspace hygiene, and local conversation delegation.", + "keywords": [ + "agent-canvas", + "openhands", + "local", + "conversation", + "delegation" + ], + "name": "agent-canvas-environment", + "source": "./skills/agent-canvas-environment" + }, + { + "category": "development", + "description": "Reference skill for the OpenHands Software Agent SDK - build AI agents with custom tools, LLM configuration, conversations, sub-agent delegation, MCP integration, security, and persistence.", + "keywords": [ + "sdk", + "agent", + "openhands", + "tools", + "llm", + "conversation" + ], + "name": "openhands-sdk", + "source": "./skills/openhands-sdk" + }, + { + "category": "integration", + "description": "Interact with Azure DevOps repositories, pull requests, and APIs using the AZURE_DEVOPS_TOKEN environment variable. Use when working with code hosted on Azure DevOps or managing Azure DevOps resources.", + "keywords": [ + "azure", + "devops", + "git", + "pull-request" + ], + "name": "azure-devops", + "source": "./skills/azure-devops" + }, + { + "category": "integration", + "description": "Bitbucket integration hub. Detects whether the repository is on Bitbucket Cloud or Bitbucket Data Center and directs you to the matching detailed skill (bitbucket-cloud or bitbucket-data-center). Use for any Bitbucket repository or pull request task.", + "keywords": [ + "bitbucket", + "git", + "pull-request" + ], + "name": "bitbucket", + "source": "./skills/bitbucket" + }, + { + "category": "integration", + "description": "Bitbucket Cloud (bitbucket.org) specifics — authenticate with BITBUCKET_TOKEN, use the REST API v2, workspace/repo_slug repositories, and the create_bitbucket_pr tool. Loaded on demand by the bitbucket skill once a Cloud environment is detected.", + "keywords": [ + "bitbucket", + "bitbucket-cloud", + "git", + "pull-request" + ], + "name": "bitbucket-cloud", + "source": "./skills/bitbucket-cloud" + }, + { + "category": "integration", + "description": "Bitbucket Data Center (self-hosted Bitbucket Server) specifics — authenticate with BITBUCKET_DATA_CENTER_TOKEN, use the REST API 1.0, PROJECT/repo_slug repositories, scm/ git remotes, and the create_bitbucket_data_center_pr tool. Loaded on demand by the bitbucket skill once a Data Center environment is detected.", + "keywords": [ + "bitbucket", + "bitbucket-data-center", + "bitbucket-server", + "git", + "pull-request" + ], + "name": "bitbucket-data-center", + "source": "./skills/bitbucket-data-center" + }, + { + "category": "utilities", + "description": "Get current weather, time, and precipitation forecast for any city using the free Open-Meteo API. Provides slash command /city-weather:now .", + "keywords": [ + "weather", + "time", + "forecast", + "temperature", + "precipitation", + "sample" + ], + "name": "city-weather", + "source": "./plugins/city-weather" + }, + { + "category": "code-quality", + "description": "Rigorous code review focusing on data structures, simplicity, security, pragmatism, and risk/safety evaluation. Provides brutally honest, actionable feedback on pull requests or merge requests, including a risk assessment for every review. Use when reviewing code changes.", + "keywords": [ + "code-review", + "quality", + "security", + "style", + "risk" + ], + "name": "code-review", + "source": "./skills/code-review" + }, + { + "category": "monitoring", + "description": "Query and analyze Datadog logs, metrics, APM traces, and monitors using the Datadog API. Use when debugging production issues, monitoring application performance, or investigating alerts.", + "keywords": [ + "datadog", + "monitoring", + "logs", + "metrics", + "apm" + ], + "name": "datadog", + "source": "./skills/datadog" + }, + { + "category": "development", + "description": "Common project operations using Deno (tasks, run/test/lint/fmt, and dependency management).", + "keywords": [ + "deno", + "typescript", + "javascript", + "runtime" + ], + "name": "deno", + "source": "./skills/deno" + }, + { + "category": "integration", + "description": "Build and automate Discord integrations (bots, webhooks, slash commands, and REST API workflows). Use when the user mentions Discord, a Discord server/guild, channels, webhooks, bot tokens, slash commands/application commands, discord.js, or discord.py.", + "keywords": [ + "discord", + "bot", + "webhook", + "automation" + ], + "name": "discord", + "source": "./skills/discord" + }, + { + "category": "infrastructure", + "description": "Run Docker commands within a container environment, including starting the Docker daemon and managing containers. Use when building, running, or managing Docker containers and images.", + "keywords": [ + "docker", + "container", + "images" + ], + "name": "docker", + "source": "./skills/docker" + }, + { + "category": "testing", + "description": "A test skill that responds to the magic word 'flarglebargle' with a compliment. Use for testing skill activation and trigger functionality.", + "keywords": [ + "test", + "demo" + ], + "name": "flarglebargle", + "source": "./skills/flarglebargle" + }, + { + "category": "design", + "description": "Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications. Generates creative, polished code and UI design that avoids generic AI aesthetics.", + "keywords": [ + "frontend", + "design", + "ui", + "web", + "react", + "html", + "css" + ], + "name": "frontend-design", + "source": "./skills/frontend-design" + }, + { + "category": "integration", + "description": "Interact with GitHub repositories, pull requests, issues, and workflows using the GITHUB_TOKEN environment variable and GitHub CLI. Use when working with code hosted on GitHub or managing GitHub resources.", + "keywords": [ + "github", + "git", + "pull-request", + "issues", + "workflows" + ], + "name": "github", + "source": "./skills/github" + }, + { + "category": "integration", + "description": "Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating workflows, or troubleshooting GitHub Actions.", + "keywords": [ + "github-actions", + "workflows", + "ci-cd", + "automation", + "actions" + ], + "name": "github-actions", + "source": "./skills/github-actions" + }, + { + "category": "code-quality", + "description": "Post structured PR reviews to GitHub with inline comments/suggestions in a single API call.", + "keywords": [ + "github", + "pull-request", + "review", + "code-review" + ], + "name": "github-pr-review", + "source": "./skills/github-pr-review" + }, + { + "category": "productivity", + "description": "Create a cron automation that polls a GitHub repository for issue and PR comments containing a configurable trigger phrase (@OpenHands by default). Starts an OpenHands conversation with full issue/PR context, posts acknowledgement comments with a conversation link, and summarises results back to the issue/PR when the agent finishes.", + "keywords": [ + "github", + "monitor", + "issues", + "pull-requests", + "trigger", + "cron", + "automation", + "integration" + ], + "name": "github-repo-monitor", + "source": "./skills/github-repo-monitor" + }, + { + "category": "integration", + "description": "Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when working with code hosted on GitLab or managing GitLab resources.", + "keywords": [ + "gitlab", + "git", + "merge-request" + ], + "name": "gitlab", + "source": "./skills/gitlab" + }, + { + "category": "data-science", + "description": "Read, modify, execute, and convert Jupyter notebooks programmatically. Use when working with .ipynb files for data science workflows, including editing cells, clearing outputs, or converting to other formats.", + "keywords": [ + "jupyter", + "notebook", + "ipynb", + "data-science" + ], + "name": "jupyter", + "source": "./skills/jupyter" + }, + { + "category": "infrastructure", + "description": "Set up and manage local Kubernetes clusters using KIND (Kubernetes IN Docker). Use when testing Kubernetes applications locally or developing cloud-native workloads.", + "keywords": [ + "kubernetes", + "k8s", + "kind", + "cloud-native" + ], + "name": "kubernetes", + "source": "./skills/kubernetes" + }, + { + "category": "code-quality", + "description": "Distill code review feedback from GitHub PRs into reusable skills and guidelines. Use when users ask to learn from code reviews, extract review patterns, or generate coding standards from historical PR feedback.", + "keywords": [ + "code-review", + "learning", + "skills", + "guidelines", + "pr-feedback" + ], + "name": "learn-from-code-review", + "source": "./skills/learn-from-code-review" + }, + { + "category": "integration", + "description": "Interact with Linear project management - query issues, update status, create tickets using the Linear GraphQL API.", + "keywords": [ + "linear", + "ticket", + "issue", + "project-management", + "graphql" + ], + "name": "linear", + "source": "./skills/linear" + }, + { + "category": "testing", + "description": "A simple test plugin for verifying plugin loading. Triggers on magic words (alakazam, abracadabra) and returns a specific phrase to confirm plugins are working.", + "keywords": [ + "test", + "magic", + "plugin", + "verification", + "sample" + ], + "name": "magic-test", + "source": "./plugins/magic-test" + }, + { + "category": "productivity", + "description": "Create, search, and update Notion pages/databases using the Notion API. Use for documenting work, generating runbooks, and automating knowledge base updates.", + "keywords": [ + "notion", + "documentation", + "knowledge-base" + ], + "name": "notion", + "source": "./skills/notion" + }, + { + "category": "development", + "description": "Handle npm package installation in non-interactive environments by piping confirmations. Use when installing Node.js packages that require user confirmation prompts.", + "keywords": [ + "npm", + "nodejs", + "packages" + ], + "name": "npm", + "source": "./skills/npm" + }, + { + "category": "productivity", + "description": "Assess repository agent-readiness across five pillars, propose high-impact fixes, and generate repo-specific AGENTS.md files.", + "keywords": [ + "onboarding", + "readiness", + "agents-md", + "agent-readiness", + "assessment" + ], + "name": "onboarding", + "source": "./plugins/onboarding" + }, + { + "category": "openhands", + "description": "Unified OpenHands plugin — bundles Cloud CLI, REST API (openhands-api), and Automations (openhands-automation) into a single plugin.", + "keywords": [ + "openhands", + "cloud", + "api", + "automation", + "cli" + ], + "name": "openhands", + "source": "./plugins/openhands" + }, + { + "category": "development", + "description": "Use the OpenHands Cloud REST API (V1) and agent-server APIs to create and manage Cloud or local backend conversations, including multi-conversation delegation workflows. Includes minimal Python and TypeScript clients under scripts/.", + "keywords": [ + "openhands", + "api", + "cloud", + "automation", + "delegation", + "agent-server", + "sandbox", + "conversations" + ], + "name": "openhands-api", + "source": "./skills/openhands-api" + }, + { + "category": "documentation", + "description": "Install and use pdflatex to compile LaTeX documents into PDFs on Linux. Use when generating academic papers, research publications, or any documents written in LaTeX.", + "keywords": [ + "latex", + "pdf", + "academic", + "documents" + ], + "name": "pdflatex", + "source": "./skills/pdflatex" + }, + { + "category": "code-quality", + "description": "Automated PR code review — analyzes diffs and posts inline review comments via the GitHub API.", + "keywords": [ + "pr-review", + "code-review", + "github", + "automation" + ], + "name": "pr-review", + "source": "./plugins/pr-review" + }, + { + "category": "quality-assurance", + "description": "Validate pull request changes by actually running the code — setting up the environment, exercising changed behavior, and posting a structured QA report.", + "keywords": [ + "qa", + "testing", + "pull-request", + "validation", + "automation" + ], + "name": "qa-changes", + "source": "./plugins/qa-changes" + }, + { + "category": "productivity", + "description": "Generate a Product Requirements Document (PRD) for a new feature through an interactive clarifying-question workflow. Use when planning a feature, starting a new project, or when asked to create a PRD.", + "keywords": [ + "prd", + "requirements", + "planning", + "product", + "specification" + ], + "name": "prd", + "source": "./skills/prd" + }, + { + "category": "productivity", + "description": "Generate consistent, well-structured release notes from git history. Produces categorized changelog with breaking changes, features, fixes, and contributor attribution.", + "keywords": [ + "release-notes", + "changelog", + "git", + "semver" + ], + "name": "release-notes", + "source": "./plugins/release-notes" + }, + { + "category": "security", + "description": "Security best practices for secure coding, authentication, authorization, and data protection. Use when developing features that handle sensitive data, user authentication, or require security review.", + "keywords": [ + "security", + "authentication", + "authorization", + "encryption" + ], + "name": "security", + "source": "./skills/security" + }, + { + "category": "development", + "description": "Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.", + "keywords": [ + "skill", + "plugin", + "create" + ], + "name": "skill-creator", + "source": "./skills/skill-creator" + }, + { + "category": "productivity", + "description": "Create a cron automation that polls up to 10 Slack channels every minute and starts an OpenHands conversation when a configurable trigger phrase is detected. Forwards thread replies to running conversations and posts summaries back to Slack when the agent finishes.", + "keywords": [ + "slack", + "monitor", + "channel", + "trigger", + "cron", + "automation", + "integration" + ], + "name": "slack-channel-monitor", + "source": "./skills/slack-channel-monitor" + }, + { + "category": "infrastructure", + "description": "Establish and manage SSH connections to remote machines, including key generation, configuration, and file transfers. Use when connecting to remote servers, executing remote commands, or transferring files via SCP.", + "keywords": [ + "ssh", + "remote", + "scp", + "server" + ], + "name": "ssh", + "source": "./skills/ssh" + }, + { + "category": "development", + "description": "Install and configure Swift programming language on Debian Linux for server-side development. Use when building Swift applications on Linux or setting up a Swift development environment.", + "keywords": [ + "swift", + "linux", + "server-side" + ], + "name": "swift-linux", + "source": "./skills/swift-linux" + }, + { + "category": "design", + "description": "Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.", + "keywords": [ + "theme", + "styling", + "design", + "slides", + "documents" + ], + "name": "theme-factory", + "source": "./skills/theme-factory" + }, + { + "category": "development", + "description": "Common project, dependency, and environment operations using uv.", + "keywords": [ + "uv", + "python", + "dependencies", + "venv" + ], + "name": "uv", + "source": "./skills/uv" + }, + { + "category": "integration", + "description": "Deploy and manage applications on Vercel, including preview deployments and deployment protection.", + "keywords": [ + "vercel", + "deployment", + "preview", + "hosting" + ], + "name": "vercel", + "source": "./skills/vercel" + }, + { + "category": "security", + "description": "Automated security vulnerability scanning and AI-powered remediation. Scans repositories, skips when no issues found, and creates PRs with fixes.", + "keywords": [ + "security", + "vulnerability", + "remediation", + "scanning", + "automation" + ], + "name": "vulnerability-remediation", + "source": "./plugins/vulnerability-remediation" + }, + { + "category": "productivity", + "description": "Iterate on a GitHub pull request — drive it through CI, code review, and QA until merge-ready. Monitors state, fixes failures, addresses review feedback, retries flaky checks, and pushes fixes in one continuous loop.", + "keywords": [ + "github", + "ci", + "review", + "qa", + "pull-request", + "iterate" + ], + "name": "iterate", + "source": "./skills/iterate" + }, + { + "category": "productivity", + "description": "Back factual claims and field values with official, verifiable sources. Use when the user asks to fill fields, answer questions, or make claims that must be supported by an exact quote and an official link.", + "keywords": [ + "evidence", + "citations", + "sources", + "verification", + "documentation", + "official" + ], + "name": "evidence-based-citations", + "source": "./skills/evidence-based-citations" + }, + { + "category": "productivity", + "description": "Create an automation that reviews GitHub pull requests when they are opened or updated. Inspects the diff, changed files, tests, and existing discussion via GitHub MCP, then posts a concise review highlighting risks, security issues, missing tests, and next steps.", + "keywords": [ + "github", + "pull-request", + "review", + "code-review", + "automation", + "integration" + ], + "name": "github-pr-reviewer", + "source": "./skills/github-pr-reviewer" + }, + { + "category": "productivity", + "description": "Create an automation that drafts incident retrospectives by gathering incident-channel messages from Slack, collecting linked tickets from Linear, and publishing a retrospective draft to Notion with timeline, impact summary, root-cause hypotheses, and action items.", + "keywords": [ + "incident", + "retrospective", + "postmortem", + "slack", + "linear", + "notion", + "automation" + ], + "name": "incident-retrospective", + "source": "./skills/incident-retrospective" + }, + { + "category": "productivity", + "description": "Create an automation that triages new Linear issues by inspecting title, description, team, and recent related issues. Suggests labels, priority, likely owner, and potential duplicates, then posts a clarifying comment.", + "keywords": [ + "linear", + "triage", + "issues", + "labels", + "priority", + "automation", + "integration" + ], + "name": "linear-triage", + "source": "./skills/linear-triage" + }, + { + "category": "productivity", + "description": "Create a recurring automation that researches a topic using Tavily web search and publishes a structured brief to Notion with executive summary, key findings, implications, and source citations.", + "keywords": [ + "research", + "brief", + "tavily", + "notion", + "web-search", + "automation" + ], + "name": "research-brief", + "source": "./skills/research-brief" + }, + { + "category": "productivity", + "description": "Create an automation that generates an async standup digest from Slack. Searches selected channels for messages since the previous workday, groups updates by project, highlights blockers and decisions, and posts a summary to a target channel.", + "keywords": [ + "slack", + "standup", + "digest", + "summary", + "daily", + "cron", + "automation" + ], + "name": "slack-standup-digest", + "source": "./skills/slack-standup-digest" + }, + { + "category": "productivity", + "description": "Write and edit clear, accessible prose in a plain English content style: active voice, front-loaded content, sentence case, and accessible formatting.", + "keywords": [ + "plain-english" + ], + "name": "plain-english-content", + "source": "./skills/plain-english-content" + }, + { + "category": "productivity", + "description": "Deploy a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable label (default: create-pr) and spawns an agent conversation to create a GitHub pull request for each new issue found. The target GitHub repo is read from the ticket body - no repo parameter required at deploy time.", + "keywords": [ + "jira", + "atlassian" + ], + "name": "jira-issue-to-pr", + "source": "./skills/jira-issue-to-pr" + } + ] +} diff --git a/.codex-plugin b/.codex-plugin deleted file mode 120000 index 665797f0..00000000 --- a/.codex-plugin +++ /dev/null @@ -1 +0,0 @@ -.plugin \ No newline at end of file diff --git a/.codex-plugin/marketplace.json b/.codex-plugin/marketplace.json new file mode 100644 index 00000000..55dbe082 --- /dev/null +++ b/.codex-plugin/marketplace.json @@ -0,0 +1,752 @@ +{ + "metadata": { + "description": "Official skills and plugins for OpenHands — the open-source AI software engineer.", + "homepage": "https://github.com/OpenHands/extensions", + "maintainer": "OpenHands" + }, + "name": "openhands-extensions", + "owner": { + "email": "contact@all-hands.dev", + "name": "OpenHands" + }, + "plugins": [ + { + "category": "development", + "description": "Create file-based sub-agents as Markdown files — no Python code required. Guides the user through a structured interview and generates a ready-to-deploy .md agent file following the OpenHands SDK specification.", + "keywords": [ + "agent", + "sub-agent", + "file-based", + "markdown", + "no-code", + "create" + ], + "name": "agent-creator", + "source": "./skills/agent-creator" + }, + { + "category": "productivity", + "description": "Add (import) an OpenHands skill from a GitHub repository into the current workspace.", + "keywords": [ + "skill", + "import", + "github", + "sparse-checkout" + ], + "name": "add-skill", + "source": "./skills/add-skill" + }, + { + "category": "productivity", + "description": "Persist and retrieve repository-specific knowledge using AGENTS.md files. Use when you want to save important information about a codebase (build commands, code style, workflows) for future sessions.", + "keywords": [ + "memory", + "knowledge", + "persistence", + "agents" + ], + "name": "agent-memory", + "source": "./skills/agent-memory" + }, + { + "category": "development", + "description": "Guided workflow for building custom AI agents using the OpenHands Software Agent SDK. Use when you want to create a new agent through an interactive interview process that gathers requirements and generates implementation plans.", + "keywords": [ + "agent", + "sdk", + "builder", + "openhands" + ], + "name": "agent-sdk-builder", + "source": "./skills/agent-sdk-builder" + }, + { + "category": "development", + "description": "Simplifies and refines code across three dimensions - code reuse, code quality, and efficiency - while preserving all functionality. Analyzes recently modified code and provides actionable improvement suggestions.", + "keywords": [ + "simplify", + "refine", + "cleanup", + "code-quality", + "reuse", + "efficiency", + "refactor" + ], + "name": "code-simplifier", + "source": "./skills/code-simplifier" + }, + { + "category": "integration", + "description": "Create and manage OpenHands automations - scheduled tasks that run in sandboxes. Use the prompt preset to create automations from natural language, or manage existing automations.", + "keywords": [ + "automation", + "cron", + "scheduled-task", + "sandbox", + "openhands" + ], + "name": "openhands-automation", + "source": "./skills/openhands-automation" + }, + { + "category": "development", + "description": "Work effectively inside a local Agent Canvas environment, including local agent-server auth, safe workspace hygiene, and local conversation delegation.", + "keywords": [ + "agent-canvas", + "openhands", + "local", + "conversation", + "delegation" + ], + "name": "agent-canvas-environment", + "source": "./skills/agent-canvas-environment" + }, + { + "category": "development", + "description": "Reference skill for the OpenHands Software Agent SDK - build AI agents with custom tools, LLM configuration, conversations, sub-agent delegation, MCP integration, security, and persistence.", + "keywords": [ + "sdk", + "agent", + "openhands", + "tools", + "llm", + "conversation" + ], + "name": "openhands-sdk", + "source": "./skills/openhands-sdk" + }, + { + "category": "integration", + "description": "Interact with Azure DevOps repositories, pull requests, and APIs using the AZURE_DEVOPS_TOKEN environment variable. Use when working with code hosted on Azure DevOps or managing Azure DevOps resources.", + "keywords": [ + "azure", + "devops", + "git", + "pull-request" + ], + "name": "azure-devops", + "source": "./skills/azure-devops" + }, + { + "category": "integration", + "description": "Bitbucket integration hub. Detects whether the repository is on Bitbucket Cloud or Bitbucket Data Center and directs you to the matching detailed skill (bitbucket-cloud or bitbucket-data-center). Use for any Bitbucket repository or pull request task.", + "keywords": [ + "bitbucket", + "git", + "pull-request" + ], + "name": "bitbucket", + "source": "./skills/bitbucket" + }, + { + "category": "integration", + "description": "Bitbucket Cloud (bitbucket.org) specifics — authenticate with BITBUCKET_TOKEN, use the REST API v2, workspace/repo_slug repositories, and the create_bitbucket_pr tool. Loaded on demand by the bitbucket skill once a Cloud environment is detected.", + "keywords": [ + "bitbucket", + "bitbucket-cloud", + "git", + "pull-request" + ], + "name": "bitbucket-cloud", + "source": "./skills/bitbucket-cloud" + }, + { + "category": "integration", + "description": "Bitbucket Data Center (self-hosted Bitbucket Server) specifics — authenticate with BITBUCKET_DATA_CENTER_TOKEN, use the REST API 1.0, PROJECT/repo_slug repositories, scm/ git remotes, and the create_bitbucket_data_center_pr tool. Loaded on demand by the bitbucket skill once a Data Center environment is detected.", + "keywords": [ + "bitbucket", + "bitbucket-data-center", + "bitbucket-server", + "git", + "pull-request" + ], + "name": "bitbucket-data-center", + "source": "./skills/bitbucket-data-center" + }, + { + "category": "utilities", + "description": "Get current weather, time, and precipitation forecast for any city using the free Open-Meteo API. Provides slash command /city-weather:now .", + "keywords": [ + "weather", + "time", + "forecast", + "temperature", + "precipitation", + "sample" + ], + "name": "city-weather", + "source": "./plugins/city-weather" + }, + { + "category": "code-quality", + "description": "Rigorous code review focusing on data structures, simplicity, security, pragmatism, and risk/safety evaluation. Provides brutally honest, actionable feedback on pull requests or merge requests, including a risk assessment for every review. Use when reviewing code changes.", + "keywords": [ + "code-review", + "quality", + "security", + "style", + "risk" + ], + "name": "code-review", + "source": "./skills/code-review" + }, + { + "category": "monitoring", + "description": "Query and analyze Datadog logs, metrics, APM traces, and monitors using the Datadog API. Use when debugging production issues, monitoring application performance, or investigating alerts.", + "keywords": [ + "datadog", + "monitoring", + "logs", + "metrics", + "apm" + ], + "name": "datadog", + "source": "./skills/datadog" + }, + { + "category": "development", + "description": "Common project operations using Deno (tasks, run/test/lint/fmt, and dependency management).", + "keywords": [ + "deno", + "typescript", + "javascript", + "runtime" + ], + "name": "deno", + "source": "./skills/deno" + }, + { + "category": "integration", + "description": "Build and automate Discord integrations (bots, webhooks, slash commands, and REST API workflows). Use when the user mentions Discord, a Discord server/guild, channels, webhooks, bot tokens, slash commands/application commands, discord.js, or discord.py.", + "keywords": [ + "discord", + "bot", + "webhook", + "automation" + ], + "name": "discord", + "source": "./skills/discord" + }, + { + "category": "infrastructure", + "description": "Run Docker commands within a container environment, including starting the Docker daemon and managing containers. Use when building, running, or managing Docker containers and images.", + "keywords": [ + "docker", + "container", + "images" + ], + "name": "docker", + "source": "./skills/docker" + }, + { + "category": "testing", + "description": "A test skill that responds to the magic word 'flarglebargle' with a compliment. Use for testing skill activation and trigger functionality.", + "keywords": [ + "test", + "demo" + ], + "name": "flarglebargle", + "source": "./skills/flarglebargle" + }, + { + "category": "design", + "description": "Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications. Generates creative, polished code and UI design that avoids generic AI aesthetics.", + "keywords": [ + "frontend", + "design", + "ui", + "web", + "react", + "html", + "css" + ], + "name": "frontend-design", + "source": "./skills/frontend-design" + }, + { + "category": "integration", + "description": "Interact with GitHub repositories, pull requests, issues, and workflows using the GITHUB_TOKEN environment variable and GitHub CLI. Use when working with code hosted on GitHub or managing GitHub resources.", + "keywords": [ + "github", + "git", + "pull-request", + "issues", + "workflows" + ], + "name": "github", + "source": "./skills/github" + }, + { + "category": "integration", + "description": "Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating workflows, or troubleshooting GitHub Actions.", + "keywords": [ + "github-actions", + "workflows", + "ci-cd", + "automation", + "actions" + ], + "name": "github-actions", + "source": "./skills/github-actions" + }, + { + "category": "code-quality", + "description": "Post structured PR reviews to GitHub with inline comments/suggestions in a single API call.", + "keywords": [ + "github", + "pull-request", + "review", + "code-review" + ], + "name": "github-pr-review", + "source": "./skills/github-pr-review" + }, + { + "category": "productivity", + "description": "Create a cron automation that polls a GitHub repository for issue and PR comments containing a configurable trigger phrase (@OpenHands by default). Starts an OpenHands conversation with full issue/PR context, posts acknowledgement comments with a conversation link, and summarises results back to the issue/PR when the agent finishes.", + "keywords": [ + "github", + "monitor", + "issues", + "pull-requests", + "trigger", + "cron", + "automation", + "integration" + ], + "name": "github-repo-monitor", + "source": "./skills/github-repo-monitor" + }, + { + "category": "integration", + "description": "Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when working with code hosted on GitLab or managing GitLab resources.", + "keywords": [ + "gitlab", + "git", + "merge-request" + ], + "name": "gitlab", + "source": "./skills/gitlab" + }, + { + "category": "data-science", + "description": "Read, modify, execute, and convert Jupyter notebooks programmatically. Use when working with .ipynb files for data science workflows, including editing cells, clearing outputs, or converting to other formats.", + "keywords": [ + "jupyter", + "notebook", + "ipynb", + "data-science" + ], + "name": "jupyter", + "source": "./skills/jupyter" + }, + { + "category": "infrastructure", + "description": "Set up and manage local Kubernetes clusters using KIND (Kubernetes IN Docker). Use when testing Kubernetes applications locally or developing cloud-native workloads.", + "keywords": [ + "kubernetes", + "k8s", + "kind", + "cloud-native" + ], + "name": "kubernetes", + "source": "./skills/kubernetes" + }, + { + "category": "code-quality", + "description": "Distill code review feedback from GitHub PRs into reusable skills and guidelines. Use when users ask to learn from code reviews, extract review patterns, or generate coding standards from historical PR feedback.", + "keywords": [ + "code-review", + "learning", + "skills", + "guidelines", + "pr-feedback" + ], + "name": "learn-from-code-review", + "source": "./skills/learn-from-code-review" + }, + { + "category": "integration", + "description": "Interact with Linear project management - query issues, update status, create tickets using the Linear GraphQL API.", + "keywords": [ + "linear", + "ticket", + "issue", + "project-management", + "graphql" + ], + "name": "linear", + "source": "./skills/linear" + }, + { + "category": "testing", + "description": "A simple test plugin for verifying plugin loading. Triggers on magic words (alakazam, abracadabra) and returns a specific phrase to confirm plugins are working.", + "keywords": [ + "test", + "magic", + "plugin", + "verification", + "sample" + ], + "name": "magic-test", + "source": "./plugins/magic-test" + }, + { + "category": "productivity", + "description": "Create, search, and update Notion pages/databases using the Notion API. Use for documenting work, generating runbooks, and automating knowledge base updates.", + "keywords": [ + "notion", + "documentation", + "knowledge-base" + ], + "name": "notion", + "source": "./skills/notion" + }, + { + "category": "development", + "description": "Handle npm package installation in non-interactive environments by piping confirmations. Use when installing Node.js packages that require user confirmation prompts.", + "keywords": [ + "npm", + "nodejs", + "packages" + ], + "name": "npm", + "source": "./skills/npm" + }, + { + "category": "productivity", + "description": "Assess repository agent-readiness across five pillars, propose high-impact fixes, and generate repo-specific AGENTS.md files.", + "keywords": [ + "onboarding", + "readiness", + "agents-md", + "agent-readiness", + "assessment" + ], + "name": "onboarding", + "source": "./plugins/onboarding" + }, + { + "category": "openhands", + "description": "Unified OpenHands plugin — bundles Cloud CLI, REST API (openhands-api), and Automations (openhands-automation) into a single plugin.", + "keywords": [ + "openhands", + "cloud", + "api", + "automation", + "cli" + ], + "name": "openhands", + "source": "./plugins/openhands" + }, + { + "category": "development", + "description": "Use the OpenHands Cloud REST API (V1) and agent-server APIs to create and manage Cloud or local backend conversations, including multi-conversation delegation workflows. Includes minimal Python and TypeScript clients under scripts/.", + "keywords": [ + "openhands", + "api", + "cloud", + "automation", + "delegation", + "agent-server", + "sandbox", + "conversations" + ], + "name": "openhands-api", + "source": "./skills/openhands-api" + }, + { + "category": "documentation", + "description": "Install and use pdflatex to compile LaTeX documents into PDFs on Linux. Use when generating academic papers, research publications, or any documents written in LaTeX.", + "keywords": [ + "latex", + "pdf", + "academic", + "documents" + ], + "name": "pdflatex", + "source": "./skills/pdflatex" + }, + { + "category": "code-quality", + "description": "Automated PR code review — analyzes diffs and posts inline review comments via the GitHub API.", + "keywords": [ + "pr-review", + "code-review", + "github", + "automation" + ], + "name": "pr-review", + "source": "./plugins/pr-review" + }, + { + "category": "quality-assurance", + "description": "Validate pull request changes by actually running the code — setting up the environment, exercising changed behavior, and posting a structured QA report.", + "keywords": [ + "qa", + "testing", + "pull-request", + "validation", + "automation" + ], + "name": "qa-changes", + "source": "./plugins/qa-changes" + }, + { + "category": "productivity", + "description": "Generate a Product Requirements Document (PRD) for a new feature through an interactive clarifying-question workflow. Use when planning a feature, starting a new project, or when asked to create a PRD.", + "keywords": [ + "prd", + "requirements", + "planning", + "product", + "specification" + ], + "name": "prd", + "source": "./skills/prd" + }, + { + "category": "productivity", + "description": "Generate consistent, well-structured release notes from git history. Produces categorized changelog with breaking changes, features, fixes, and contributor attribution.", + "keywords": [ + "release-notes", + "changelog", + "git", + "semver" + ], + "name": "release-notes", + "source": "./plugins/release-notes" + }, + { + "category": "security", + "description": "Security best practices for secure coding, authentication, authorization, and data protection. Use when developing features that handle sensitive data, user authentication, or require security review.", + "keywords": [ + "security", + "authentication", + "authorization", + "encryption" + ], + "name": "security", + "source": "./skills/security" + }, + { + "category": "development", + "description": "Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.", + "keywords": [ + "skill", + "plugin", + "create" + ], + "name": "skill-creator", + "source": "./skills/skill-creator" + }, + { + "category": "productivity", + "description": "Create a cron automation that polls up to 10 Slack channels every minute and starts an OpenHands conversation when a configurable trigger phrase is detected. Forwards thread replies to running conversations and posts summaries back to Slack when the agent finishes.", + "keywords": [ + "slack", + "monitor", + "channel", + "trigger", + "cron", + "automation", + "integration" + ], + "name": "slack-channel-monitor", + "source": "./skills/slack-channel-monitor" + }, + { + "category": "infrastructure", + "description": "Establish and manage SSH connections to remote machines, including key generation, configuration, and file transfers. Use when connecting to remote servers, executing remote commands, or transferring files via SCP.", + "keywords": [ + "ssh", + "remote", + "scp", + "server" + ], + "name": "ssh", + "source": "./skills/ssh" + }, + { + "category": "development", + "description": "Install and configure Swift programming language on Debian Linux for server-side development. Use when building Swift applications on Linux or setting up a Swift development environment.", + "keywords": [ + "swift", + "linux", + "server-side" + ], + "name": "swift-linux", + "source": "./skills/swift-linux" + }, + { + "category": "design", + "description": "Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.", + "keywords": [ + "theme", + "styling", + "design", + "slides", + "documents" + ], + "name": "theme-factory", + "source": "./skills/theme-factory" + }, + { + "category": "development", + "description": "Common project, dependency, and environment operations using uv.", + "keywords": [ + "uv", + "python", + "dependencies", + "venv" + ], + "name": "uv", + "source": "./skills/uv" + }, + { + "category": "integration", + "description": "Deploy and manage applications on Vercel, including preview deployments and deployment protection.", + "keywords": [ + "vercel", + "deployment", + "preview", + "hosting" + ], + "name": "vercel", + "source": "./skills/vercel" + }, + { + "category": "security", + "description": "Automated security vulnerability scanning and AI-powered remediation. Scans repositories, skips when no issues found, and creates PRs with fixes.", + "keywords": [ + "security", + "vulnerability", + "remediation", + "scanning", + "automation" + ], + "name": "vulnerability-remediation", + "source": "./plugins/vulnerability-remediation" + }, + { + "category": "productivity", + "description": "Iterate on a GitHub pull request — drive it through CI, code review, and QA until merge-ready. Monitors state, fixes failures, addresses review feedback, retries flaky checks, and pushes fixes in one continuous loop.", + "keywords": [ + "github", + "ci", + "review", + "qa", + "pull-request", + "iterate" + ], + "name": "iterate", + "source": "./skills/iterate" + }, + { + "category": "productivity", + "description": "Back factual claims and field values with official, verifiable sources. Use when the user asks to fill fields, answer questions, or make claims that must be supported by an exact quote and an official link.", + "keywords": [ + "evidence", + "citations", + "sources", + "verification", + "documentation", + "official" + ], + "name": "evidence-based-citations", + "source": "./skills/evidence-based-citations" + }, + { + "category": "productivity", + "description": "Create an automation that reviews GitHub pull requests when they are opened or updated. Inspects the diff, changed files, tests, and existing discussion via GitHub MCP, then posts a concise review highlighting risks, security issues, missing tests, and next steps.", + "keywords": [ + "github", + "pull-request", + "review", + "code-review", + "automation", + "integration" + ], + "name": "github-pr-reviewer", + "source": "./skills/github-pr-reviewer" + }, + { + "category": "productivity", + "description": "Create an automation that drafts incident retrospectives by gathering incident-channel messages from Slack, collecting linked tickets from Linear, and publishing a retrospective draft to Notion with timeline, impact summary, root-cause hypotheses, and action items.", + "keywords": [ + "incident", + "retrospective", + "postmortem", + "slack", + "linear", + "notion", + "automation" + ], + "name": "incident-retrospective", + "source": "./skills/incident-retrospective" + }, + { + "category": "productivity", + "description": "Create an automation that triages new Linear issues by inspecting title, description, team, and recent related issues. Suggests labels, priority, likely owner, and potential duplicates, then posts a clarifying comment.", + "keywords": [ + "linear", + "triage", + "issues", + "labels", + "priority", + "automation", + "integration" + ], + "name": "linear-triage", + "source": "./skills/linear-triage" + }, + { + "category": "productivity", + "description": "Create a recurring automation that researches a topic using Tavily web search and publishes a structured brief to Notion with executive summary, key findings, implications, and source citations.", + "keywords": [ + "research", + "brief", + "tavily", + "notion", + "web-search", + "automation" + ], + "name": "research-brief", + "source": "./skills/research-brief" + }, + { + "category": "productivity", + "description": "Create an automation that generates an async standup digest from Slack. Searches selected channels for messages since the previous workday, groups updates by project, highlights blockers and decisions, and posts a summary to a target channel.", + "keywords": [ + "slack", + "standup", + "digest", + "summary", + "daily", + "cron", + "automation" + ], + "name": "slack-standup-digest", + "source": "./skills/slack-standup-digest" + }, + { + "category": "productivity", + "description": "Write and edit clear, accessible prose in a plain English content style: active voice, front-loaded content, sentence case, and accessible formatting.", + "keywords": [ + "plain-english" + ], + "name": "plain-english-content", + "source": "./skills/plain-english-content" + }, + { + "category": "productivity", + "description": "Deploy a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable label (default: create-pr) and spawns an agent conversation to create a GitHub pull request for each new issue found. The target GitHub repo is read from the ticket body - no repo parameter required at deploy time.", + "keywords": [ + "jira", + "atlassian" + ], + "name": "jira-issue-to-pr", + "source": "./skills/jira-issue-to-pr" + } + ] +} diff --git a/.plugin/marketplace.json b/.plugin/marketplace.json deleted file mode 120000 index adad5692..00000000 --- a/.plugin/marketplace.json +++ /dev/null @@ -1 +0,0 @@ -../marketplaces/openhands-extensions.json \ No newline at end of file diff --git a/.plugin/marketplace.json b/.plugin/marketplace.json new file mode 100644 index 00000000..55dbe082 --- /dev/null +++ b/.plugin/marketplace.json @@ -0,0 +1,752 @@ +{ + "metadata": { + "description": "Official skills and plugins for OpenHands — the open-source AI software engineer.", + "homepage": "https://github.com/OpenHands/extensions", + "maintainer": "OpenHands" + }, + "name": "openhands-extensions", + "owner": { + "email": "contact@all-hands.dev", + "name": "OpenHands" + }, + "plugins": [ + { + "category": "development", + "description": "Create file-based sub-agents as Markdown files — no Python code required. Guides the user through a structured interview and generates a ready-to-deploy .md agent file following the OpenHands SDK specification.", + "keywords": [ + "agent", + "sub-agent", + "file-based", + "markdown", + "no-code", + "create" + ], + "name": "agent-creator", + "source": "./skills/agent-creator" + }, + { + "category": "productivity", + "description": "Add (import) an OpenHands skill from a GitHub repository into the current workspace.", + "keywords": [ + "skill", + "import", + "github", + "sparse-checkout" + ], + "name": "add-skill", + "source": "./skills/add-skill" + }, + { + "category": "productivity", + "description": "Persist and retrieve repository-specific knowledge using AGENTS.md files. Use when you want to save important information about a codebase (build commands, code style, workflows) for future sessions.", + "keywords": [ + "memory", + "knowledge", + "persistence", + "agents" + ], + "name": "agent-memory", + "source": "./skills/agent-memory" + }, + { + "category": "development", + "description": "Guided workflow for building custom AI agents using the OpenHands Software Agent SDK. Use when you want to create a new agent through an interactive interview process that gathers requirements and generates implementation plans.", + "keywords": [ + "agent", + "sdk", + "builder", + "openhands" + ], + "name": "agent-sdk-builder", + "source": "./skills/agent-sdk-builder" + }, + { + "category": "development", + "description": "Simplifies and refines code across three dimensions - code reuse, code quality, and efficiency - while preserving all functionality. Analyzes recently modified code and provides actionable improvement suggestions.", + "keywords": [ + "simplify", + "refine", + "cleanup", + "code-quality", + "reuse", + "efficiency", + "refactor" + ], + "name": "code-simplifier", + "source": "./skills/code-simplifier" + }, + { + "category": "integration", + "description": "Create and manage OpenHands automations - scheduled tasks that run in sandboxes. Use the prompt preset to create automations from natural language, or manage existing automations.", + "keywords": [ + "automation", + "cron", + "scheduled-task", + "sandbox", + "openhands" + ], + "name": "openhands-automation", + "source": "./skills/openhands-automation" + }, + { + "category": "development", + "description": "Work effectively inside a local Agent Canvas environment, including local agent-server auth, safe workspace hygiene, and local conversation delegation.", + "keywords": [ + "agent-canvas", + "openhands", + "local", + "conversation", + "delegation" + ], + "name": "agent-canvas-environment", + "source": "./skills/agent-canvas-environment" + }, + { + "category": "development", + "description": "Reference skill for the OpenHands Software Agent SDK - build AI agents with custom tools, LLM configuration, conversations, sub-agent delegation, MCP integration, security, and persistence.", + "keywords": [ + "sdk", + "agent", + "openhands", + "tools", + "llm", + "conversation" + ], + "name": "openhands-sdk", + "source": "./skills/openhands-sdk" + }, + { + "category": "integration", + "description": "Interact with Azure DevOps repositories, pull requests, and APIs using the AZURE_DEVOPS_TOKEN environment variable. Use when working with code hosted on Azure DevOps or managing Azure DevOps resources.", + "keywords": [ + "azure", + "devops", + "git", + "pull-request" + ], + "name": "azure-devops", + "source": "./skills/azure-devops" + }, + { + "category": "integration", + "description": "Bitbucket integration hub. Detects whether the repository is on Bitbucket Cloud or Bitbucket Data Center and directs you to the matching detailed skill (bitbucket-cloud or bitbucket-data-center). Use for any Bitbucket repository or pull request task.", + "keywords": [ + "bitbucket", + "git", + "pull-request" + ], + "name": "bitbucket", + "source": "./skills/bitbucket" + }, + { + "category": "integration", + "description": "Bitbucket Cloud (bitbucket.org) specifics — authenticate with BITBUCKET_TOKEN, use the REST API v2, workspace/repo_slug repositories, and the create_bitbucket_pr tool. Loaded on demand by the bitbucket skill once a Cloud environment is detected.", + "keywords": [ + "bitbucket", + "bitbucket-cloud", + "git", + "pull-request" + ], + "name": "bitbucket-cloud", + "source": "./skills/bitbucket-cloud" + }, + { + "category": "integration", + "description": "Bitbucket Data Center (self-hosted Bitbucket Server) specifics — authenticate with BITBUCKET_DATA_CENTER_TOKEN, use the REST API 1.0, PROJECT/repo_slug repositories, scm/ git remotes, and the create_bitbucket_data_center_pr tool. Loaded on demand by the bitbucket skill once a Data Center environment is detected.", + "keywords": [ + "bitbucket", + "bitbucket-data-center", + "bitbucket-server", + "git", + "pull-request" + ], + "name": "bitbucket-data-center", + "source": "./skills/bitbucket-data-center" + }, + { + "category": "utilities", + "description": "Get current weather, time, and precipitation forecast for any city using the free Open-Meteo API. Provides slash command /city-weather:now .", + "keywords": [ + "weather", + "time", + "forecast", + "temperature", + "precipitation", + "sample" + ], + "name": "city-weather", + "source": "./plugins/city-weather" + }, + { + "category": "code-quality", + "description": "Rigorous code review focusing on data structures, simplicity, security, pragmatism, and risk/safety evaluation. Provides brutally honest, actionable feedback on pull requests or merge requests, including a risk assessment for every review. Use when reviewing code changes.", + "keywords": [ + "code-review", + "quality", + "security", + "style", + "risk" + ], + "name": "code-review", + "source": "./skills/code-review" + }, + { + "category": "monitoring", + "description": "Query and analyze Datadog logs, metrics, APM traces, and monitors using the Datadog API. Use when debugging production issues, monitoring application performance, or investigating alerts.", + "keywords": [ + "datadog", + "monitoring", + "logs", + "metrics", + "apm" + ], + "name": "datadog", + "source": "./skills/datadog" + }, + { + "category": "development", + "description": "Common project operations using Deno (tasks, run/test/lint/fmt, and dependency management).", + "keywords": [ + "deno", + "typescript", + "javascript", + "runtime" + ], + "name": "deno", + "source": "./skills/deno" + }, + { + "category": "integration", + "description": "Build and automate Discord integrations (bots, webhooks, slash commands, and REST API workflows). Use when the user mentions Discord, a Discord server/guild, channels, webhooks, bot tokens, slash commands/application commands, discord.js, or discord.py.", + "keywords": [ + "discord", + "bot", + "webhook", + "automation" + ], + "name": "discord", + "source": "./skills/discord" + }, + { + "category": "infrastructure", + "description": "Run Docker commands within a container environment, including starting the Docker daemon and managing containers. Use when building, running, or managing Docker containers and images.", + "keywords": [ + "docker", + "container", + "images" + ], + "name": "docker", + "source": "./skills/docker" + }, + { + "category": "testing", + "description": "A test skill that responds to the magic word 'flarglebargle' with a compliment. Use for testing skill activation and trigger functionality.", + "keywords": [ + "test", + "demo" + ], + "name": "flarglebargle", + "source": "./skills/flarglebargle" + }, + { + "category": "design", + "description": "Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications. Generates creative, polished code and UI design that avoids generic AI aesthetics.", + "keywords": [ + "frontend", + "design", + "ui", + "web", + "react", + "html", + "css" + ], + "name": "frontend-design", + "source": "./skills/frontend-design" + }, + { + "category": "integration", + "description": "Interact with GitHub repositories, pull requests, issues, and workflows using the GITHUB_TOKEN environment variable and GitHub CLI. Use when working with code hosted on GitHub or managing GitHub resources.", + "keywords": [ + "github", + "git", + "pull-request", + "issues", + "workflows" + ], + "name": "github", + "source": "./skills/github" + }, + { + "category": "integration", + "description": "Create, debug, and test GitHub Actions workflows and custom actions. Use when building CI/CD pipelines, automating workflows, or troubleshooting GitHub Actions.", + "keywords": [ + "github-actions", + "workflows", + "ci-cd", + "automation", + "actions" + ], + "name": "github-actions", + "source": "./skills/github-actions" + }, + { + "category": "code-quality", + "description": "Post structured PR reviews to GitHub with inline comments/suggestions in a single API call.", + "keywords": [ + "github", + "pull-request", + "review", + "code-review" + ], + "name": "github-pr-review", + "source": "./skills/github-pr-review" + }, + { + "category": "productivity", + "description": "Create a cron automation that polls a GitHub repository for issue and PR comments containing a configurable trigger phrase (@OpenHands by default). Starts an OpenHands conversation with full issue/PR context, posts acknowledgement comments with a conversation link, and summarises results back to the issue/PR when the agent finishes.", + "keywords": [ + "github", + "monitor", + "issues", + "pull-requests", + "trigger", + "cron", + "automation", + "integration" + ], + "name": "github-repo-monitor", + "source": "./skills/github-repo-monitor" + }, + { + "category": "integration", + "description": "Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when working with code hosted on GitLab or managing GitLab resources.", + "keywords": [ + "gitlab", + "git", + "merge-request" + ], + "name": "gitlab", + "source": "./skills/gitlab" + }, + { + "category": "data-science", + "description": "Read, modify, execute, and convert Jupyter notebooks programmatically. Use when working with .ipynb files for data science workflows, including editing cells, clearing outputs, or converting to other formats.", + "keywords": [ + "jupyter", + "notebook", + "ipynb", + "data-science" + ], + "name": "jupyter", + "source": "./skills/jupyter" + }, + { + "category": "infrastructure", + "description": "Set up and manage local Kubernetes clusters using KIND (Kubernetes IN Docker). Use when testing Kubernetes applications locally or developing cloud-native workloads.", + "keywords": [ + "kubernetes", + "k8s", + "kind", + "cloud-native" + ], + "name": "kubernetes", + "source": "./skills/kubernetes" + }, + { + "category": "code-quality", + "description": "Distill code review feedback from GitHub PRs into reusable skills and guidelines. Use when users ask to learn from code reviews, extract review patterns, or generate coding standards from historical PR feedback.", + "keywords": [ + "code-review", + "learning", + "skills", + "guidelines", + "pr-feedback" + ], + "name": "learn-from-code-review", + "source": "./skills/learn-from-code-review" + }, + { + "category": "integration", + "description": "Interact with Linear project management - query issues, update status, create tickets using the Linear GraphQL API.", + "keywords": [ + "linear", + "ticket", + "issue", + "project-management", + "graphql" + ], + "name": "linear", + "source": "./skills/linear" + }, + { + "category": "testing", + "description": "A simple test plugin for verifying plugin loading. Triggers on magic words (alakazam, abracadabra) and returns a specific phrase to confirm plugins are working.", + "keywords": [ + "test", + "magic", + "plugin", + "verification", + "sample" + ], + "name": "magic-test", + "source": "./plugins/magic-test" + }, + { + "category": "productivity", + "description": "Create, search, and update Notion pages/databases using the Notion API. Use for documenting work, generating runbooks, and automating knowledge base updates.", + "keywords": [ + "notion", + "documentation", + "knowledge-base" + ], + "name": "notion", + "source": "./skills/notion" + }, + { + "category": "development", + "description": "Handle npm package installation in non-interactive environments by piping confirmations. Use when installing Node.js packages that require user confirmation prompts.", + "keywords": [ + "npm", + "nodejs", + "packages" + ], + "name": "npm", + "source": "./skills/npm" + }, + { + "category": "productivity", + "description": "Assess repository agent-readiness across five pillars, propose high-impact fixes, and generate repo-specific AGENTS.md files.", + "keywords": [ + "onboarding", + "readiness", + "agents-md", + "agent-readiness", + "assessment" + ], + "name": "onboarding", + "source": "./plugins/onboarding" + }, + { + "category": "openhands", + "description": "Unified OpenHands plugin — bundles Cloud CLI, REST API (openhands-api), and Automations (openhands-automation) into a single plugin.", + "keywords": [ + "openhands", + "cloud", + "api", + "automation", + "cli" + ], + "name": "openhands", + "source": "./plugins/openhands" + }, + { + "category": "development", + "description": "Use the OpenHands Cloud REST API (V1) and agent-server APIs to create and manage Cloud or local backend conversations, including multi-conversation delegation workflows. Includes minimal Python and TypeScript clients under scripts/.", + "keywords": [ + "openhands", + "api", + "cloud", + "automation", + "delegation", + "agent-server", + "sandbox", + "conversations" + ], + "name": "openhands-api", + "source": "./skills/openhands-api" + }, + { + "category": "documentation", + "description": "Install and use pdflatex to compile LaTeX documents into PDFs on Linux. Use when generating academic papers, research publications, or any documents written in LaTeX.", + "keywords": [ + "latex", + "pdf", + "academic", + "documents" + ], + "name": "pdflatex", + "source": "./skills/pdflatex" + }, + { + "category": "code-quality", + "description": "Automated PR code review — analyzes diffs and posts inline review comments via the GitHub API.", + "keywords": [ + "pr-review", + "code-review", + "github", + "automation" + ], + "name": "pr-review", + "source": "./plugins/pr-review" + }, + { + "category": "quality-assurance", + "description": "Validate pull request changes by actually running the code — setting up the environment, exercising changed behavior, and posting a structured QA report.", + "keywords": [ + "qa", + "testing", + "pull-request", + "validation", + "automation" + ], + "name": "qa-changes", + "source": "./plugins/qa-changes" + }, + { + "category": "productivity", + "description": "Generate a Product Requirements Document (PRD) for a new feature through an interactive clarifying-question workflow. Use when planning a feature, starting a new project, or when asked to create a PRD.", + "keywords": [ + "prd", + "requirements", + "planning", + "product", + "specification" + ], + "name": "prd", + "source": "./skills/prd" + }, + { + "category": "productivity", + "description": "Generate consistent, well-structured release notes from git history. Produces categorized changelog with breaking changes, features, fixes, and contributor attribution.", + "keywords": [ + "release-notes", + "changelog", + "git", + "semver" + ], + "name": "release-notes", + "source": "./plugins/release-notes" + }, + { + "category": "security", + "description": "Security best practices for secure coding, authentication, authorization, and data protection. Use when developing features that handle sensitive data, user authentication, or require security review.", + "keywords": [ + "security", + "authentication", + "authorization", + "encryption" + ], + "name": "security", + "source": "./skills/security" + }, + { + "category": "development", + "description": "Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.", + "keywords": [ + "skill", + "plugin", + "create" + ], + "name": "skill-creator", + "source": "./skills/skill-creator" + }, + { + "category": "productivity", + "description": "Create a cron automation that polls up to 10 Slack channels every minute and starts an OpenHands conversation when a configurable trigger phrase is detected. Forwards thread replies to running conversations and posts summaries back to Slack when the agent finishes.", + "keywords": [ + "slack", + "monitor", + "channel", + "trigger", + "cron", + "automation", + "integration" + ], + "name": "slack-channel-monitor", + "source": "./skills/slack-channel-monitor" + }, + { + "category": "infrastructure", + "description": "Establish and manage SSH connections to remote machines, including key generation, configuration, and file transfers. Use when connecting to remote servers, executing remote commands, or transferring files via SCP.", + "keywords": [ + "ssh", + "remote", + "scp", + "server" + ], + "name": "ssh", + "source": "./skills/ssh" + }, + { + "category": "development", + "description": "Install and configure Swift programming language on Debian Linux for server-side development. Use when building Swift applications on Linux or setting up a Swift development environment.", + "keywords": [ + "swift", + "linux", + "server-side" + ], + "name": "swift-linux", + "source": "./skills/swift-linux" + }, + { + "category": "design", + "description": "Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.", + "keywords": [ + "theme", + "styling", + "design", + "slides", + "documents" + ], + "name": "theme-factory", + "source": "./skills/theme-factory" + }, + { + "category": "development", + "description": "Common project, dependency, and environment operations using uv.", + "keywords": [ + "uv", + "python", + "dependencies", + "venv" + ], + "name": "uv", + "source": "./skills/uv" + }, + { + "category": "integration", + "description": "Deploy and manage applications on Vercel, including preview deployments and deployment protection.", + "keywords": [ + "vercel", + "deployment", + "preview", + "hosting" + ], + "name": "vercel", + "source": "./skills/vercel" + }, + { + "category": "security", + "description": "Automated security vulnerability scanning and AI-powered remediation. Scans repositories, skips when no issues found, and creates PRs with fixes.", + "keywords": [ + "security", + "vulnerability", + "remediation", + "scanning", + "automation" + ], + "name": "vulnerability-remediation", + "source": "./plugins/vulnerability-remediation" + }, + { + "category": "productivity", + "description": "Iterate on a GitHub pull request — drive it through CI, code review, and QA until merge-ready. Monitors state, fixes failures, addresses review feedback, retries flaky checks, and pushes fixes in one continuous loop.", + "keywords": [ + "github", + "ci", + "review", + "qa", + "pull-request", + "iterate" + ], + "name": "iterate", + "source": "./skills/iterate" + }, + { + "category": "productivity", + "description": "Back factual claims and field values with official, verifiable sources. Use when the user asks to fill fields, answer questions, or make claims that must be supported by an exact quote and an official link.", + "keywords": [ + "evidence", + "citations", + "sources", + "verification", + "documentation", + "official" + ], + "name": "evidence-based-citations", + "source": "./skills/evidence-based-citations" + }, + { + "category": "productivity", + "description": "Create an automation that reviews GitHub pull requests when they are opened or updated. Inspects the diff, changed files, tests, and existing discussion via GitHub MCP, then posts a concise review highlighting risks, security issues, missing tests, and next steps.", + "keywords": [ + "github", + "pull-request", + "review", + "code-review", + "automation", + "integration" + ], + "name": "github-pr-reviewer", + "source": "./skills/github-pr-reviewer" + }, + { + "category": "productivity", + "description": "Create an automation that drafts incident retrospectives by gathering incident-channel messages from Slack, collecting linked tickets from Linear, and publishing a retrospective draft to Notion with timeline, impact summary, root-cause hypotheses, and action items.", + "keywords": [ + "incident", + "retrospective", + "postmortem", + "slack", + "linear", + "notion", + "automation" + ], + "name": "incident-retrospective", + "source": "./skills/incident-retrospective" + }, + { + "category": "productivity", + "description": "Create an automation that triages new Linear issues by inspecting title, description, team, and recent related issues. Suggests labels, priority, likely owner, and potential duplicates, then posts a clarifying comment.", + "keywords": [ + "linear", + "triage", + "issues", + "labels", + "priority", + "automation", + "integration" + ], + "name": "linear-triage", + "source": "./skills/linear-triage" + }, + { + "category": "productivity", + "description": "Create a recurring automation that researches a topic using Tavily web search and publishes a structured brief to Notion with executive summary, key findings, implications, and source citations.", + "keywords": [ + "research", + "brief", + "tavily", + "notion", + "web-search", + "automation" + ], + "name": "research-brief", + "source": "./skills/research-brief" + }, + { + "category": "productivity", + "description": "Create an automation that generates an async standup digest from Slack. Searches selected channels for messages since the previous workday, groups updates by project, highlights blockers and decisions, and posts a summary to a target channel.", + "keywords": [ + "slack", + "standup", + "digest", + "summary", + "daily", + "cron", + "automation" + ], + "name": "slack-standup-digest", + "source": "./skills/slack-standup-digest" + }, + { + "category": "productivity", + "description": "Write and edit clear, accessible prose in a plain English content style: active voice, front-loaded content, sentence case, and accessible formatting.", + "keywords": [ + "plain-english" + ], + "name": "plain-english-content", + "source": "./skills/plain-english-content" + }, + { + "category": "productivity", + "description": "Deploy a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable label (default: create-pr) and spawns an agent conversation to create a GitHub pull request for each new issue found. The target GitHub repo is read from the ticket body - no repo parameter required at deploy time.", + "keywords": [ + "jira", + "atlassian" + ], + "name": "jira-issue-to-pr", + "source": "./skills/jira-issue-to-pr" + } + ] +} diff --git a/AGENTS.md b/AGENTS.md index d14211fa..de5e84fd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -105,7 +105,8 @@ When editing or adding skills in this repo, follow these rules (and add new skil ## CI / validation gotchas - The test suite expects **every directory under `skills/`** to be listed in a marketplace. If you add a new skill (or rebase onto a main branch that added skills), update the appropriate marketplace file or CI will fail with `Skills missing from marketplace: [...]`. -- `scripts/sync_extensions.py` keeps generated artifacts in sync: Claude Code command files, README catalog section, coverage checks, and vendor symlinks. Run `python scripts/sync_extensions.py --check` (or just push — CI runs it) to verify everything is consistent. Run without `--check` to auto-fix. The "Quick Start" section in `README.md` (OpenHands SDK, Claude Code, and Codex setup instructions) is **manually maintained** above the auto-generated catalog markers and is intentionally not generated by the sync script. +- `scripts/sync_extensions.py` keeps generated artifacts in sync: Claude Code command files, README catalog section, coverage checks, vendor symlinks, and root marketplace catalog copies. Run `python scripts/sync_extensions.py --check` (or just push — CI runs it) to verify everything is consistent. Run without `--check` to auto-fix. The "Quick Start" section in `README.md` (OpenHands SDK, Claude Code, and Codex setup instructions) is **manually maintained** above the auto-generated catalog markers and is intentionally not generated by the sync script. +- The repository root exposes the canonical marketplace catalog (`marketplaces/openhands-extensions.json`) as real `marketplace.json` copies under `.claude-plugin/`, `.codex-plugin/`, and `.plugin/` — **not symlinks**. `raw.githubusercontent.com` serves git symlinks as their literal target text and does not traverse symlinked directory paths, so symlinks made the catalog unreachable at the standard `.claude-plugin/marketplace.json` path (used by `github://openhands/extensions` consumers). The `root-marketplace` sync task keeps these copies byte-for-byte in sync with the canonical file; never replace them with symlinks. - The sync script uses PyYAML to parse SKILL.md frontmatter. If you add a skill with a slash trigger (e.g., `triggers: ["/mycommand"]`), the script auto-generates `commands/mycommand.md`. **Note:** Slash triggers in SKILL.md frontmatter are deprecated — prefer adding a `commands/command-name.md` file to the plugin's `commands/` directory instead. Keyword triggers (non-slash) remain the recommended way to activate skills by topic. ## OpenHands SDK documentation policy diff --git a/scripts/sync_extensions.py b/scripts/sync_extensions.py index 040ff241..b181e936 100644 --- a/scripts/sync_extensions.py +++ b/scripts/sync_extensions.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """Keep the OpenHands extensions registry in sync. -Four sync tasks, runnable individually or all at once: +Five sync tasks, runnable individually or all at once: 1. **commands** — generate Claude Code ``commands/.md`` files from SKILL.md slash-triggers. @@ -10,6 +10,12 @@ marketplace, or a marketplace entry points to a missing directory. 4. **symlinks** — enforce ``.plugin/`` as the canonical manifest directory with vendor symlinks (``.claude-plugin``, ``.codex-plugin``). + 5. **root-marketplace** — keep real ``marketplace.json`` copies at the + repository root under ``.claude-plugin/``, ``.codex-plugin/``, and + ``.plugin/`` so consumers that fetch the catalog over the GitHub raw + URL (e.g. ``github://openhands/extensions``) can read it. Git symlinks + are stored as blobs and ``raw.githubusercontent.com`` does not + dereference them through directory paths, so these must be real files. Usage: python scripts/sync_extensions.py # run all, write changes @@ -18,6 +24,7 @@ python scripts/sync_extensions.py catalog # only regenerate README catalog python scripts/sync_extensions.py coverage # only check marketplace coverage python scripts/sync_extensions.py symlinks # only check/fix vendor symlinks + python scripts/sync_extensions.py root-marketplace # only sync root marketplace copies python scripts/sync_extensions.py commands catalog # combine sub-commands """ @@ -36,6 +43,14 @@ README_PATH = REPO_ROOT / "README.md" SKILL_DIRS = [REPO_ROOT / "skills", REPO_ROOT / "plugins"] MARKETPLACES_DIR = REPO_ROOT / "marketplaces" +# The canonical marketplace catalog that the registry publishes. The +# repository root exposes copies of this file (not symlinks) under the +# vendor directories below so that consumers fetching the catalog over the +# GitHub raw URL (``github://openhands/extensions``) can read it. +PRIMARY_MARKETPLACE = MARKETPLACES_DIR / "openhands-extensions.json" +# Vendor directories at the repository root that must each contain a real +# (non-symlink) ``marketplace.json`` copy of ``PRIMARY_MARKETPLACE``. +ROOT_MARKETPLACE_DIRS = [".claude-plugin", ".codex-plugin", ".plugin"] # Max description length in the catalog table. 120 chars fits GitHub's # diff viewer and rendered Markdown tables without horizontal scroll. MAX_DESC_LEN = 120 @@ -422,6 +437,82 @@ def sync_symlinks(*, check: bool) -> list[str]: return problems +# ── 5. Root marketplace copies ─────────────────────────────────────── + + +def _normalize_marketplace_bytes(raw: bytes) -> bytes: + """Serialize marketplace JSON with sorted keys + 2-space indent. + + Produces a canonical byte string so byte-for-byte equality checks work + regardless of incidental formatting differences in the source file. + """ + return (json.dumps(json.loads(raw), indent=2, ensure_ascii=False, sort_keys=True) + "\n").encode("utf-8") + + +def sync_root_marketplace(*, check: bool) -> list[str]: + """Ensure each root vendor directory has a real marketplace.json copy. + + The registry's canonical catalog lives at + ``marketplaces/openhands-extensions.json``. Historically the root exposed + it through a double symlink chain (``.claude-plugin`` -> ``.plugin`` and + ``.plugin/marketplace.json`` -> the canonical file). ``raw.githubusercontent.com`` + serves git symlinks as their literal target text and does not traverse + symlinked directory paths, so consumers fetching + ``.claude-plugin/marketplace.json`` over the raw URL (e.g. the + plugin-directory with ``MARKETPLACE_SOURCE=github://openhands/extensions``) + received a 404 (or the literal symlink body) and saw an empty catalog. + + This sync replaces those symlinks with real directory + file copies that + mirror the canonical catalog byte-for-byte, so the catalog is reachable + at every standard ``.claude-plugin/marketplace.json`` path while staying + in sync with the single source of truth. + """ + if not PRIMARY_MARKETPLACE.is_file(): + return [f"canonical marketplace missing: {PRIMARY_MARKETPLACE.relative_to(REPO_ROOT)}"] + + canonical = _normalize_marketplace_bytes(PRIMARY_MARKETPLACE.read_bytes()) + problems: list[str] = [] + + for vendor in ROOT_MARKETPLACE_DIRS: + vendor_dir = REPO_ROOT / vendor + target = vendor_dir / "marketplace.json" + rel = target.relative_to(REPO_ROOT) + + # Classify the vendor directory. + dir_ok = vendor_dir.is_dir() and not vendor_dir.is_symlink() + if vendor_dir.is_symlink(): + problems.append(f"symlinked dir: {vendor} -> {vendor_dir.readlink()}") + elif not vendor_dir.exists(): + problems.append(f"missing dir: {vendor}") + elif not dir_ok: + problems.append(f"not a directory: {vendor}") + + # Classify the marketplace.json file (if any). + file_ok = target.is_file() and not target.is_symlink() + if target.is_symlink(): + problems.append(f"symlinked file: {rel} -> {target.readlink()}") + elif target.exists() and not file_ok: + problems.append(f"not a regular file: {rel}") + elif file_ok: + current = _normalize_marketplace_bytes(target.read_bytes()) + if current != canonical: + problems.append(f"out of date: {rel}") + else: + problems.append(f"missing: {rel}") + + if not check: + # Rebuild a real directory + real file from scratch. + if vendor_dir.is_symlink() or (vendor_dir.exists() and not vendor_dir.is_dir()): + vendor_dir.unlink() + vendor_dir.mkdir(parents=True, exist_ok=True) + if target.is_symlink() or (target.exists() and not target.is_file()): + target.unlink() + if not target.exists() or _normalize_marketplace_bytes(target.read_bytes()) != canonical: + target.write_bytes(canonical) + + return problems + + # ── Main ───────────────────────────────────────────────────────────── ALL_SYNCS = { @@ -429,6 +520,7 @@ def sync_symlinks(*, check: bool) -> list[str]: "catalog": sync_catalog, "coverage": sync_coverage, "symlinks": sync_symlinks, + "root-marketplace": sync_root_marketplace, } diff --git a/tests/test_sync_extensions.py b/tests/test_sync_extensions.py index 8dfb703d..1cad1090 100644 --- a/tests/test_sync_extensions.py +++ b/tests/test_sync_extensions.py @@ -9,8 +9,11 @@ from sync_extensions import ( CMD_MARKER, CommandSpec, + PRIMARY_MARKETPLACE, REPO_ROOT, + ROOT_MARKETPLACE_DIRS, _entry_type, + _normalize_marketplace_bytes, build_command_content, collect_needed_commands, generate_catalog, @@ -18,6 +21,7 @@ parse_frontmatter, slash_triggers, sync_commands, + sync_root_marketplace, ) @@ -304,3 +308,122 @@ def test_all_source_paths_exist(self): f"{mp_file.name}: {plugin.get('name', '?')} source " f"'{src}' does not exist at {resolved}" ) + + +# ── root marketplace copies ────────────────────────────────────────── + +class TestRootMarketplace: + """The root vendor marketplace.json files must be real (non-symlink) copies. + + raw.githubusercontent.com does not dereference git symlinks through + directory paths, so consumers using the standard + ``.claude-plugin/marketplace.json`` path (e.g. plugin-directory with + ``MARKETPLACE_SOURCE=github://openhands/extensions``) need real files. + """ + + def test_vendor_dirs_are_real_directories(self): + for vendor in ROOT_MARKETPLACE_DIRS: + vendor_dir = REPO_ROOT / vendor + assert vendor_dir.is_dir(), f"{vendor}/ is not a directory" + assert not vendor_dir.is_symlink(), ( + f"{vendor} is a symlink; raw.githubusercontent.com cannot " + "traverse symlinked directory paths" + ) + + def test_marketplace_json_files_are_real_files(self): + for vendor in ROOT_MARKETPLACE_DIRS: + target = REPO_ROOT / vendor / "marketplace.json" + assert target.is_file(), f"{target} is missing" + assert not target.is_symlink(), ( + f"{target} is a symlink; raw.githubusercontent.com serves " + "symlink blobs as their literal target text, not the catalog" + ) + + def test_marketplace_json_matches_canonical(self): + canonical = _normalize_marketplace_bytes(PRIMARY_MARKETPLACE.read_bytes()) + for vendor in ROOT_MARKETPLACE_DIRS: + target = REPO_ROOT / vendor / "marketplace.json" + current = _normalize_marketplace_bytes(target.read_bytes()) + assert current == canonical, ( + f"{target.relative_to(REPO_ROOT)} is out of sync with " + f"{PRIMARY_MARKETPLACE.relative_to(REPO_ROOT)}" + ) + + def test_marketplace_json_is_valid_catalog(self): + import json + + canonical = json.loads(PRIMARY_MARKETPLACE.read_bytes()) + for vendor in ROOT_MARKETPLACE_DIRS: + target = REPO_ROOT / vendor / "marketplace.json" + data = json.loads(target.read_bytes()) + assert data.get("name") == canonical.get("name") + assert len(data.get("plugins", [])) == len(canonical.get("plugins", [])) + + def test_sync_root_marketplace_detects_and_fixes_symlinks(self, tmp_path, monkeypatch): + """sync_root_marketplace replaces symlinked dirs/files with real copies.""" + import json + + monkeypatch.setattr("sync_extensions.REPO_ROOT", tmp_path) + monkeypatch.setattr("sync_extensions.PRIMARY_MARKETPLACE", tmp_path / "marketplaces" / "openhands-extensions.json") + + # Canonical marketplace source. + mp_dir = tmp_path / "marketplaces" + mp_dir.mkdir() + canonical_data = {"name": "openhands-extensions", "plugins": [{"name": "x", "source": "./skills/x"}]} + canonical_bytes = (json.dumps(canonical_data, indent=2, ensure_ascii=False, sort_keys=True) + "\n").encode() + (mp_dir / "openhands-extensions.json").write_bytes(canonical_bytes) + + # Recreate the broken double-symlink chain from the issue. + plugin_dir = tmp_path / ".plugin" + plugin_dir.mkdir() + (plugin_dir / "marketplace.json").symlink_to("../marketplaces/openhands-extensions.json") + (tmp_path / ".claude-plugin").symlink_to(".plugin") + (tmp_path / ".codex-plugin").symlink_to(".plugin") + + # Check mode must report the symlinks as problems. + problems = sync_root_marketplace(check=True) + assert any("symlinked dir" in p for p in problems) + assert any("symlinked file" in p for p in problems) + + # Write mode fixes them. + sync_root_marketplace(check=False) + for vendor in [".claude-plugin", ".codex-plugin", ".plugin"]: + vendor_dir = tmp_path / vendor + target = vendor_dir / "marketplace.json" + assert vendor_dir.is_dir() and not vendor_dir.is_symlink(), f"{vendor} still a symlink dir" + assert target.is_file() and not target.is_symlink(), f"{target} still a symlink file" + assert _normalize_marketplace_bytes(target.read_bytes()) == canonical_bytes + + # After fixing, check mode is clean. + assert sync_root_marketplace(check=True) == [] + + def test_sync_root_marketplace_detects_stale_copy(self, tmp_path, monkeypatch): + """sync_root_marketplace reports (and fixes) an out-of-date real copy.""" + import json + + monkeypatch.setattr("sync_extensions.REPO_ROOT", tmp_path) + monkeypatch.setattr("sync_extensions.PRIMARY_MARKETPLACE", tmp_path / "marketplaces" / "openhands-extensions.json") + + mp_dir = tmp_path / "marketplaces" + mp_dir.mkdir() + canonical = {"name": "openhands-extensions", "plugins": [{"name": "x", "source": "./skills/x"}]} + canonical_bytes = (json.dumps(canonical, indent=2, ensure_ascii=False, sort_keys=True) + "\n").encode() + (mp_dir / "openhands-extensions.json").write_bytes(canonical_bytes) + + stale = {"name": "openhands-extensions", "plugins": []} + for vendor in [".claude-plugin", ".codex-plugin", ".plugin"]: + (tmp_path / vendor).mkdir() + (tmp_path / vendor / "marketplace.json").write_text(json.dumps(stale)) + + problems = sync_root_marketplace(check=True) + assert len(problems) == 3 + assert all("out of date" in p for p in problems) + + sync_root_marketplace(check=False) + for vendor in [".claude-plugin", ".codex-plugin", ".plugin"]: + assert _normalize_marketplace_bytes((tmp_path / vendor / "marketplace.json").read_bytes()) == canonical_bytes + assert sync_root_marketplace(check=True) == [] + + +if __name__ == "__main__": + pytest.main([__file__, "-v"])