build: native subagent pipeline + Codex-only asset producer

Adds an agent cross-compile pipeline alongside the existing skill
pipeline. Sources live at skill/agents/*.md; providers that declare
agentFormat (codex-toml, claude-md) emit native subagent files. An
optional providers: <list> field on an agent gates which harnesses
get a copy; default (no field) ships everywhere.

The impeccable-asset-producer agent is opt-in to Codex only. It's
useful for Codex's native image generation path and is untested
elsewhere; Claude has no native image gen anyway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-05-12 22:46:55 -07:00
co-authored by Claude Opus 4.7
parent b03d7515c8
commit fd3eed9f3b
10 changed files with 421 additions and 7 deletions
+31 -1
View File
@@ -390,7 +390,7 @@ This folder contains skills for all supported tools:
.cursor/ -> Cursor
.claude/ -> Claude Code
.gemini/ -> Gemini CLI
.codex/ -> Legacy bundle folder in this ZIP (Codex CLI uses .agents/)
.codex/ -> Codex custom agents (Codex skills use .agents/)
.agents/ -> Codex CLI
.github/ -> GitHub Copilot
.kiro/ -> Kiro
@@ -662,6 +662,18 @@ async function build() {
}
}
for (const { provider, configDir, agentFormat } of Object.values(PROVIDERS)) {
if (!agentFormat) continue;
const agentsSrc = path.join(DIST_DIR, provider, configDir, 'agents');
const agentsDest = path.join(ROOT_DIR, configDir, 'agents');
if (fs.existsSync(agentsDest)) fs.rmSync(agentsDest, { recursive: true, force: true });
if (fs.existsSync(agentsSrc)) {
copyDirSync(agentsSrc, agentsDest);
}
}
// Remove deprecated skill stubs from local harness dirs. They exist
// in dist/ so the cleanup script can redirect users, but they should
// not clutter the repo's own skill directories.
@@ -691,15 +703,29 @@ async function build() {
const pluginRoot = path.join(ROOT_DIR, 'plugin');
const pluginManifestDir = path.join(pluginRoot, '.claude-plugin');
const pluginSkillsDir = path.join(pluginRoot, 'skills');
const pluginAgentsDir = path.join(pluginRoot, 'agents');
if (fs.existsSync(pluginManifestDir)) fs.rmSync(pluginManifestDir, { recursive: true });
if (fs.existsSync(pluginSkillsDir)) fs.rmSync(pluginSkillsDir, { recursive: true });
if (fs.existsSync(pluginAgentsDir)) fs.rmSync(pluginAgentsDir, { recursive: true });
const rootManifest = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, '.claude-plugin/plugin.json'), 'utf-8'));
const claudeAgentsSrc = path.join(DIST_DIR, 'claude-code', '.claude', 'agents');
const pluginAgentEntries = fs.existsSync(claudeAgentsSrc)
? fs.readdirSync(claudeAgentsSrc)
.filter(file => file.endsWith('.md'))
.sort()
.map(file => `./agents/${file}`)
: [];
// Trailing slash on the skills path matches the documented schema in
// code.claude.com/docs/en/plugins-reference. Issue #86 has 3 reporters
// converging on "add trailing slash to fix slash commands not registering";
// the docs schema example consistently uses `"./custom/skills/"` form.
const pluginManifest = { ...rootManifest, skills: './skills/' };
if (pluginAgentEntries.length) {
pluginManifest.agents = pluginAgentEntries;
} else {
delete pluginManifest.agents;
}
fs.mkdirSync(pluginManifestDir, { recursive: true });
fs.writeFileSync(
path.join(pluginManifestDir, 'plugin.json'),
@@ -712,6 +738,10 @@ async function build() {
copyDirSync(claudeSkillsSrc, path.join(pluginSkillsDir, 'impeccable'));
}
if (fs.existsSync(claudeAgentsSrc)) {
copyDirSync(claudeAgentsSrc, pluginAgentsDir);
}
console.log('📦 Built Claude Code plugin subtree at ./plugin/');
// Generate authoritative counts and validate references