(self, plugin: PluginSource, skill: SkillSource, result: EmitResult)
| 440 | # ── Internals ────────────────────────────────────────────────────────── |
| 441 | |
| 442 | def _emit_skill(self, plugin: PluginSource, skill: SkillSource, result: EmitResult) -> None: |
| 443 | skill_id = f"{plugin.name}__{skill.name}" |
| 444 | skill_dir = Path(".codex") / "skills" / skill_id |
| 445 | |
| 446 | fm = _filter_frontmatter(skill.frontmatter, _CLAUDE_ONLY_SKILL_FIELDS) |
| 447 | # Codex requires `name` to match directory exactly. |
| 448 | fm["name"] = skill_id |
| 449 | |
| 450 | body = _rewrite_body_for_codex(skill.body).rstrip() + "\n" |
| 451 | head, overflow = _split_body_if_oversized(body, self.SKILL_BODY_CAP) |
| 452 | if overflow: |
| 453 | # If source already has references/details.md, route overflow to _overflow.md |
| 454 | # so the source mirror pass below doesn't clobber it. |
| 455 | source_has_details = ( |
| 456 | skill.references_dir is not None and (skill.references_dir / "details.md").is_file() |
| 457 | ) |
| 458 | overflow_rel = "_overflow.md" if source_has_details else "details.md" |
| 459 | result.warnings.append( |
| 460 | f"skill `{skill_id}` body exceeded {self.SKILL_BODY_CAP}B; " |
| 461 | f"split into references/{overflow_rel}" |
| 462 | ) |
| 463 | result.written.append( |
| 464 | self.write(skill_dir / "references" / overflow_rel, overflow.rstrip() + "\n") |
| 465 | ) |
| 466 | |
| 467 | content = _frontmatter_block(fm) + "\n\n" + head |
| 468 | result.written.append(self.write(skill_dir / "SKILL.md", content)) |
| 469 | |
| 470 | # Mirror any existing references/ assets — use binary copy so non-text assets |
| 471 | # (PDFs, images, fonts) don't crash the run with UnicodeDecodeError. |
| 472 | # The overflow vs source-details collision was handled above by routing |
| 473 | # overflow to references/_overflow.md when source already has details.md. |
| 474 | if skill.references_dir: |
| 475 | for ref in sorted(skill.references_dir.rglob("*")): |
| 476 | if not ref.is_file(): |
| 477 | continue |
| 478 | rel = ref.relative_to(skill.references_dir) |
| 479 | result.written.append(self.mirror_file(ref, skill_dir / "references" / rel)) |
| 480 | |
| 481 | def _emit_agent(self, plugin: PluginSource, agent: AgentSource, result: EmitResult) -> None: |
| 482 | agent_id = f"{plugin.name}__{agent.name}" |
no test coverage detected