Skip to content

Commit 9045204

Browse files
tmeschterCopilot
andcommitted
Support external plugins in marketplace.json generation
The marketplace currently only includes plugins that live as local directories in plugins/. This makes it impossible to list plugins hosted in external GitHub repos, npm packages, or other git URLs. Add plugins/external.json as a hand-curated list of external plugin entries following the Claude Code plugin marketplace spec. The generate-marketplace script now reads this file and merges external entries as-is into the generated marketplace.json, sorted by name. Changes: - Add plugins/external.json (empty array, ready for entries) - Update eng/generate-marketplace.mjs to load, merge, and sort external plugins; warn on duplicate names; log counts - Document the external plugin workflow in CONTRIBUTING.md and AGENTS.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 833a5c9 commit 9045204

4 files changed

Lines changed: 79 additions & 1 deletion

File tree

AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ When adding a new agent, instruction, skill, hook, workflow, or plugin:
151151
5. Run `npm run build` to update README.md and marketplace.json
152152
6. Verify the plugin appears in `.github/plugin/marketplace.json`
153153

154+
**For External Plugins:**
155+
1. Edit `plugins/external.json` and add an entry with `name`, `source`, and `description`
156+
2. The `source` field should be an object specifying a GitHub repo, git URL, npm package, or pip package (see [CONTRIBUTING.md](CONTRIBUTING.md#adding-external-plugins))
157+
3. Run `npm run build` to regenerate marketplace.json
158+
4. Verify the external plugin appears in `.github/plugin/marketplace.json`
159+
154160
### Testing Instructions
155161

156162
```bash

CONTRIBUTING.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,34 @@ plugins/my-plugin-id/
152152
- **Clear purpose**: The plugin should solve a specific problem or workflow
153153
- **Validate before submitting**: Run `npm run plugin:validate` to ensure your plugin is valid
154154

155+
#### Adding External Plugins
156+
157+
External plugins are plugins hosted outside this repository (e.g., in a GitHub repo, npm package, or git URL). They are listed in `plugins/external.json` and merged into the generated `marketplace.json` during build.
158+
159+
To add an external plugin, append an entry to `plugins/external.json` following the [Claude Code plugin marketplace spec](https://code.claude.com/docs/en/plugin-marketplaces#plugin-entries). Each entry requires `name` and `source` at minimum:
160+
161+
```json
162+
[
163+
{
164+
"name": "my-external-plugin",
165+
"source": {
166+
"source": "github",
167+
"repo": "owner/plugin-repo"
168+
},
169+
"description": "Description of the external plugin",
170+
"version": "1.0.0"
171+
}
172+
]
173+
```
174+
175+
Supported source types:
176+
- **GitHub**: `{ "source": "github", "repo": "owner/repo", "ref": "v1.0.0" }`
177+
- **Git URL**: `{ "source": "url", "url": "https://gitlab.com/team/plugin.git" }`
178+
- **npm**: `{ "source": "npm", "package": "@scope/package", "version": "1.0.0" }`
179+
- **pip**: `{ "source": "pip", "package": "package-name", "version": "1.0.0" }`
180+
181+
After editing `plugins/external.json`, run `npm run build` to regenerate `marketplace.json`.
182+
155183
### Adding Hooks
156184

157185
Hooks enable automated workflows triggered by specific events during GitHub Copilot coding agent sessions, such as session start, session end, user prompts, and tool usage.

eng/generate-marketplace.mjs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,32 @@ import path from "path";
55
import { ROOT_FOLDER } from "./constants.mjs";
66

77
const PLUGINS_DIR = path.join(ROOT_FOLDER, "plugins");
8+
const EXTERNAL_PLUGINS_FILE = path.join(ROOT_FOLDER, "plugins", "external.json");
89
const MARKETPLACE_FILE = path.join(ROOT_FOLDER, ".github/plugin", "marketplace.json");
910

11+
/**
12+
* Read external plugin entries from external.json
13+
* @returns {Array} - Array of external plugin entries (merged as-is)
14+
*/
15+
function readExternalPlugins() {
16+
if (!fs.existsSync(EXTERNAL_PLUGINS_FILE)) {
17+
return [];
18+
}
19+
20+
try {
21+
const content = fs.readFileSync(EXTERNAL_PLUGINS_FILE, "utf8");
22+
const plugins = JSON.parse(content);
23+
if (!Array.isArray(plugins)) {
24+
console.warn("Warning: external.json must contain an array");
25+
return [];
26+
}
27+
return plugins;
28+
} catch (error) {
29+
console.error(`Error reading external.json: ${error.message}`);
30+
return [];
31+
}
32+
}
33+
1034
/**
1135
* Read plugin metadata from plugin.json file
1236
* @param {string} pluginDir - Path to plugin directory
@@ -67,6 +91,25 @@ function generateMarketplace() {
6791
}
6892
}
6993

94+
// Read external plugins and merge as-is
95+
const externalPlugins = readExternalPlugins();
96+
if (externalPlugins.length > 0) {
97+
console.log(`\nFound ${externalPlugins.length} external plugins`);
98+
99+
// Warn on duplicate names
100+
const localNames = new Set(plugins.map(p => p.name));
101+
for (const ext of externalPlugins) {
102+
if (localNames.has(ext.name)) {
103+
console.warn(`Warning: external plugin "${ext.name}" has the same name as a local plugin`);
104+
}
105+
plugins.push(ext);
106+
console.log(`✓ Added external plugin: ${ext.name}`);
107+
}
108+
}
109+
110+
// Sort all plugins by name (case-insensitive)
111+
plugins.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
112+
70113
// Create marketplace.json structure
71114
const marketplace = {
72115
name: "awesome-copilot",
@@ -91,7 +134,7 @@ function generateMarketplace() {
91134
// Write marketplace.json
92135
fs.writeFileSync(MARKETPLACE_FILE, JSON.stringify(marketplace, null, 2) + "\n");
93136

94-
console.log(`\n✓ Successfully generated marketplace.json with ${plugins.length} plugins`);
137+
console.log(`\n✓ Successfully generated marketplace.json with ${plugins.length} plugins (${plugins.length - externalPlugins.length} local, ${externalPlugins.length} external)`);
95138
console.log(` Location: ${MARKETPLACE_FILE}`);
96139
}
97140

plugins/external.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]

0 commit comments

Comments
 (0)