Skip to content

Comments

fix: rewrite plugin.json paths to folders during publish#807

Merged
aaronpowell merged 1 commit intostagedfrom
fix/rewrite-plugin-json-on-publish
Feb 24, 2026
Merged

fix: rewrite plugin.json paths to folders during publish#807
aaronpowell merged 1 commit intostagedfrom
fix/rewrite-plugin-json-on-publish

Conversation

@aaronpowell
Copy link
Contributor

During the staged→main publish, after materializing files into plugin directories, the materialize script now rewrites each plugin.json to replace individual file paths with folder references:

  • "agents": ["./agents/foo.md"]"agents": ["./agents"]
  • "commands": ["./commands/x.md"]"commands": ["./commands"]
  • "skills": ["./skills/baz/"]"skills": ["./skills/baz"]

This ensures main branch plugin.json files reference directories (where materialized files live) rather than individual source file paths from staged.

During the staged→main publish, after materializing files into plugin
directories, rewrite each plugin.json to replace individual file paths
with folder references so consumers on main get directory-level entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 24, 2026 23:23
@aaronpowell aaronpowell merged commit 078570c into staged Feb 24, 2026
4 checks passed
@aaronpowell aaronpowell deleted the fix/rewrite-plugin-json-on-publish branch February 24, 2026 23:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the publish-time plugin materialization step so that after copying source content into each plugin directory, plugin.json is rewritten to reference directories (e.g. ./agents, ./commands, ./skills/<name>) instead of individual file paths.

Changes:

  • After materialization, rewrite agents and commands paths in each plugin’s plugin.json to their parent directories.
  • Normalize skills paths by stripping a trailing slash.
  • Write the updated plugin.json back to disk during publish.
Comments suppressed due to low confidence (3)

eng/materialize-plugins.mjs:156

  • Rewriting agents/commands entries from individual ./agents/foo.md paths to directory paths (e.g. ./agents) breaks existing consumers that treat these arrays as item-level resources. For example, eng/generate-website-data.mjs builds plugin.items by mapping each data.agents/data.commands entry to a clickable file path; if this becomes a directory, the modal will attempt to fetch file content for a folder and fail. Unless all downstream consumers (website data generation, modal, any installers) are updated to expand directories into concrete files, this rewrite should not be done (or should be written to a separate publish-only manifest).
    // Rewrite plugin.json to use folder paths instead of individual file paths.
    // On staged, paths like ./agents/foo.md point to individual source files.
    // On main, after materialization, we only need the containing directory.
    const rewritten = { ...metadata };
    let changed = false;

    for (const field of ["agents", "commands"]) {
      if (Array.isArray(rewritten[field]) && rewritten[field].length > 0) {
        const dirs = [...new Set(rewritten[field].map(p => path.dirname(p)))];

eng/materialize-plugins.mjs:159

  • This rewrite is not idempotent: if plugin.json already contains directory entries (e.g. after one publish), path.dirname("./agents") becomes ".", which would corrupt the manifest on subsequent runs. Consider only rewriting entries that match the expected file pattern (e.g. start with ./agents/ and end with .md / ./commands/ + .md), and leave already-directory entries unchanged.
    for (const field of ["agents", "commands"]) {
      if (Array.isArray(rewritten[field]) && rewritten[field].length > 0) {
        const dirs = [...new Set(rewritten[field].map(p => path.dirname(p)))];
        rewritten[field] = dirs;
        changed = true;
      }

eng/materialize-plugins.mjs:166

  • changed is set to true for skills whenever the array is non-empty, even if none of the paths had a trailing slash to strip. This causes unnecessary rewrites of plugin.json (no functional change, but adds churn). Consider only setting changed when at least one element is actually modified.
    if (Array.isArray(rewritten.skills) && rewritten.skills.length > 0) {
      // Skills are already folder refs (./skills/name/); strip trailing slash
      rewritten.skills = rewritten.skills.map(p => p.replace(/\/$/, ""));
      changed = true;
    }

Comment on lines +148 to +171
// Rewrite plugin.json to use folder paths instead of individual file paths.
// On staged, paths like ./agents/foo.md point to individual source files.
// On main, after materialization, we only need the containing directory.
const rewritten = { ...metadata };
let changed = false;

for (const field of ["agents", "commands"]) {
if (Array.isArray(rewritten[field]) && rewritten[field].length > 0) {
const dirs = [...new Set(rewritten[field].map(p => path.dirname(p)))];
rewritten[field] = dirs;
changed = true;
}
}

if (Array.isArray(rewritten.skills) && rewritten.skills.length > 0) {
// Skills are already folder refs (./skills/name/); strip trailing slash
rewritten.skills = rewritten.skills.map(p => p.replace(/\/$/, ""));
changed = true;
}

if (changed) {
fs.writeFileSync(pluginJsonPath, JSON.stringify(rewritten, null, 2) + "\n", "utf8");
}

Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

This produces plugin.json values (e.g. "agents": ["./agents"]) that no longer satisfy the repository’s own plugin manifest validation rules: eng/validate-plugins.mjs currently enforces that agents/commands entries start with ./agents//./commands/ and end with .md (and skills end with /). If plugin.json on main is intentionally different, the validator (and any tooling depending on this schema) should be updated accordingly or split into staged-vs-main manifests.

This issue also appears in the following locations of the same file:

  • line 148
  • line 154
  • line 162
Suggested change
// Rewrite plugin.json to use folder paths instead of individual file paths.
// On staged, paths like ./agents/foo.md point to individual source files.
// On main, after materialization, we only need the containing directory.
const rewritten = { ...metadata };
let changed = false;
for (const field of ["agents", "commands"]) {
if (Array.isArray(rewritten[field]) && rewritten[field].length > 0) {
const dirs = [...new Set(rewritten[field].map(p => path.dirname(p)))];
rewritten[field] = dirs;
changed = true;
}
}
if (Array.isArray(rewritten.skills) && rewritten.skills.length > 0) {
// Skills are already folder refs (./skills/name/); strip trailing slash
rewritten.skills = rewritten.skills.map(p => p.replace(/\/$/, ""));
changed = true;
}
if (changed) {
fs.writeFileSync(pluginJsonPath, JSON.stringify(rewritten, null, 2) + "\n", "utf8");
}

Copilot uses AI. Check for mistakes.
Sign up for free to 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.

1 participant