Skip to content

feat: initialize Claude Code marketplace with test plugins and GitHub Pages - #1

Closed
fx wants to merge 5 commits into
mainfrom
feat/initial-marketplace-setup
Closed

feat: initialize Claude Code marketplace with test plugins and GitHub Pages#1
fx wants to merge 5 commits into
mainfrom
feat/initial-marketplace-setup

Conversation

@fx

@fxfx commented Nov 2, 2025

Copy link
Copy Markdown
Owner

Summary

This PR implements Phase 1 of the Claude Code marketplace infrastructure:

  • Initialize repository structure with README, LICENSE, and .gitignore
  • Add marketplace.json manifest with plugin metadata
  • Create test-skill plugin to verify marketplace functionality
  • Create test-agent plugin to verify marketplace functionality
  • Configure GitHub Pages deployment with marketplace browser

Changes

Repository Structure:

  • README.md with installation instructions (chezmoi + manual)
  • MIT License
  • .gitignore for common dev artifacts

Marketplace Manifest:

  • marketplace.json defining plugin metadata schema
  • Two test plugins registered (test-skill, test-agent)

Test Plugins:

  • skills/test-skill.md - Verifies skill loading from marketplace
  • agents/test-agent.md - Verifies agent loading from marketplace

GitHub Pages:

  • .github/workflows/pages.yml - Automated deployment workflow
  • index.html - Interactive marketplace browser
  • Displays all plugins from marketplace.json dynamically

Testing

After merge:

  1. GitHub Pages will deploy automatically to https://fx.github.io/cc/
  2. Users can browse available plugins in the web interface
  3. Test plugins can be installed via chezmoi external sources
  4. Verify integration with dotfiles repository in Phase 2

Next Steps

Phase 2 will update the dotfiles repository to:

  • Add chezmoi external configuration for cc marketplace
  • Update installation scripts to include marketplace plugins
  • Add profile-based conditional installation

CopilotAI review requested due to automatic review settings November 2, 2025 23:20

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR establishes a Claude Code Marketplace repository with initial test plugins and a web interface. It provides infrastructure for distributing Claude Code agents, skills, and commands through a centralized marketplace that can be installed via chezmoi or manually.

  • Creates marketplace infrastructure with a JSON manifest and GitHub Pages deployment
  • Adds test plugins (test-skill and test-agent) to verify marketplace functionality
  • Provides installation instructions via chezmoi and manual methods

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
skills/test-skill.mdAdds a test skill with metadata and instructions for verifying marketplace functionality
marketplace.jsonCreates marketplace manifest listing available plugins with metadata
index.htmlImplements web interface for browsing marketplace plugins with dynamic loading
agents/test-agent.mdAdds a test agent for verifying marketplace integration
README.mdProvides documentation for installation, structure, and contribution guidelines
LICENSEAdds MIT license for the marketplace
.gitignoreConfigures ignored files for macOS, IDE, and build artifacts
.github/workflows/pages.ymlSets up GitHub Actions workflow for deploying to GitHub Pages

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadindex.html
Comment on lines +179 to +192

const tags = plugin.tags.map(tag =>
'<span class="tag">' + tag + '</span>'
).join('');

card.innerHTML = '<div class="plugin-type">' + plugin.type + '</div>' +
'<div class="plugin-name">' + plugin.name + '</div>' +
'<div class="plugin-description">' + plugin.description + '</div>' +
'<div class="tags">' + tags + '</div>' +
'<div class="plugin-meta">' +
'<span>v' + plugin.version + '</span>' +
'<span>by ' + plugin.author + '</span>' +
'</div>';

CopilotAINov 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User-supplied data from marketplace.json is being inserted into the DOM without sanitization. If plugin.name, plugin.description, plugin.type, plugin.version, or plugin.author contain HTML/JavaScript, this creates an XSS vulnerability. Use textContent instead of innerHTML or sanitize the input before insertion.

Suggested change
const tags = plugin.tags.map(tag =>
'<spanclass="tag">' + tag + '</span>'
).join('');
card.innerHTML = '<divclass="plugin-type">' + plugin.type + '</div>' +
'<divclass="plugin-name">' + plugin.name + '</div>' +
'<divclass="plugin-description">' + plugin.description + '</div>' +
'<divclass="tags">' + tags + '</div>' +
'<divclass="plugin-meta">' +
'<span>v' + plugin.version + '</span>' +
'<span>by ' + plugin.author + '</span>' +
'</div>';
// Plugin type
const typeDiv = document.createElement('div');
typeDiv.className = 'plugin-type';
typeDiv.textContent = plugin.type;
card.appendChild(typeDiv);
// Plugin name
const nameDiv = document.createElement('div');
nameDiv.className = 'plugin-name';
nameDiv.textContent = plugin.name;
card.appendChild(nameDiv);
// Plugin description
const descDiv = document.createElement('div');
descDiv.className = 'plugin-description';
descDiv.textContent = plugin.description;
card.appendChild(descDiv);
// Tags
const tagsDiv = document.createElement('div');
tagsDiv.className = 'tags';
if (Array.isArray(plugin.tags)) {
plugin.tags.forEach(tag => {
const tagSpan = document.createElement('span');
tagSpan.className = 'tag';
tagSpan.textContent = tag;
tagsDiv.appendChild(tagSpan);
});
}
card.appendChild(tagsDiv);
// Meta info
const metaDiv = document.createElement('div');
metaDiv.className = 'plugin-meta';
const versionSpan = document.createElement('span');
versionSpan.textContent = 'v' + plugin.version;
metaDiv.appendChild(versionSpan);
const authorSpan = document.createElement('span');
authorSpan.textContent = 'by ' + plugin.author;
metaDiv.appendChild(authorSpan);
card.appendChild(metaDiv);

Copilot uses AI. Check for mistakes.
Comment threadindex.html
Comment on lines +179 to +192

const tags = plugin.tags.map(tag =>
'<span class="tag">' + tag + '</span>'
).join('');

card.innerHTML = '<div class="plugin-type">' + plugin.type + '</div>' +
'<div class="plugin-name">' + plugin.name + '</div>' +
'<div class="plugin-description">' + plugin.description + '</div>' +
'<div class="tags">' + tags + '</div>' +
'<div class="plugin-meta">' +
'<span>v' + plugin.version + '</span>' +
'<span>by ' + plugin.author + '</span>' +
'</div>';

CopilotAINov 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tag values from marketplace.json are concatenated into HTML without sanitization. This creates an XSS vulnerability if tags contain malicious HTML/JavaScript. Use textContent for text nodes or sanitize the input.

Suggested change
const tags = plugin.tags.map(tag =>
'<spanclass="tag">' + tag + '</span>'
).join('');
card.innerHTML = '<divclass="plugin-type">' + plugin.type + '</div>' +
'<divclass="plugin-name">' + plugin.name + '</div>' +
'<divclass="plugin-description">' + plugin.description + '</div>' +
'<divclass="tags">' + tags + '</div>' +
'<divclass="plugin-meta">' +
'<span>v' + plugin.version + '</span>' +
'<span>by ' + plugin.author + '</span>' +
'</div>';
// Plugin type
const typeDiv = document.createElement('div');
typeDiv.className = 'plugin-type';
typeDiv.textContent = plugin.type;
card.appendChild(typeDiv);
// Plugin name
const nameDiv = document.createElement('div');
nameDiv.className = 'plugin-name';
nameDiv.textContent = plugin.name;
card.appendChild(nameDiv);
// Plugin description
const descDiv = document.createElement('div');
descDiv.className = 'plugin-description';
descDiv.textContent = plugin.description;
card.appendChild(descDiv);
// Tags
const tagsDiv = document.createElement('div');
tagsDiv.className = 'tags';
plugin.tags.forEach(tag => {
const tagSpan = document.createElement('span');
tagSpan.className = 'tag';
tagSpan.textContent = tag;
tagsDiv.appendChild(tagSpan);
});
card.appendChild(tagsDiv);
// Plugin meta
const metaDiv = document.createElement('div');
metaDiv.className = 'plugin-meta';
const versionSpan = document.createElement('span');
versionSpan.textContent = 'v' + plugin.version;
metaDiv.appendChild(versionSpan);
const authorSpan = document.createElement('span');
authorSpan.textContent = 'by ' + plugin.author;
metaDiv.appendChild(authorSpan);
card.appendChild(metaDiv);

Copilot uses AI. Check for mistakes.
@fx

fx commented Nov 3, 2025

Copy link
Copy Markdown
OwnerAuthor

Closing this PR as it has been superseded by PR #2 (#2).

PR #2 includes all valuable content from this PR (LICENSE, .gitignore, GitHub Pages workflow) and follows the correct Claude Code marketplace structure with .claude-plugin/ directory and self-contained plugins.

All changes have been incorporated into PR #2 which is now ready for review and merge.

@fxfx closed this Nov 3, 2025
@fx
fx deleted the feat/initial-marketplace-setup branch November 3, 2025 21:49
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@fx