Compare commits
10 Commits
418d9a8857
...
a3cef61d5d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3cef61d5d | ||
|
|
36e7f3a370 | ||
|
|
63ab7cbc3a | ||
|
|
49100ef3d1 | ||
|
|
ea202c0373 | ||
|
|
1dea33c305 | ||
|
|
2eae6ad21a | ||
|
|
12b83e683f | ||
|
|
907746f83e | ||
|
|
ab38e2ffd0 |
@@ -11,14 +11,14 @@
|
||||
"plugins": [
|
||||
{
|
||||
"name": "compound-engineering",
|
||||
"description": "AI-powered development tools that get smarter with every use. Make each unit of engineering work easier than the last. Includes 27 specialized agents, 23 commands, and 14 skills.",
|
||||
"version": "2.27.0",
|
||||
"description": "AI-powered development tools that get smarter with every use. Make each unit of engineering work easier than the last. Includes 28 specialized agents, 24 commands, and 15 skills.",
|
||||
"version": "2.28.0",
|
||||
"author": {
|
||||
"name": "Kieran Klaassen",
|
||||
"url": "https://github.com/kieranklaassen",
|
||||
"email": "kieran@every.to"
|
||||
},
|
||||
"homepage": "https://github.com/kieranklaassen/compound-engineering-plugin",
|
||||
"homepage": "https://github.com/EveryInc/compound-engineering-plugin",
|
||||
"tags": ["ai-powered", "compound-engineering", "workflow-automation", "code-review", "quality", "knowledge-management", "image-generation"],
|
||||
"source": "./plugins/compound-engineering"
|
||||
},
|
||||
@@ -29,7 +29,7 @@
|
||||
"author": {
|
||||
"name": "Nityesh Agarwal"
|
||||
},
|
||||
"homepage": "https://github.com/kieranklaassen/compound-engineering-plugin",
|
||||
"homepage": "https://github.com/EveryInc/compound-engineering-plugin",
|
||||
"tags": ["coding", "programming", "tutorial", "learning", "spaced-repetition", "education"],
|
||||
"source": "./plugins/coding-tutor"
|
||||
}
|
||||
|
||||
25
.github/workflows/ci.yml
vendored
Normal file
25
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Run tests
|
||||
run: bun test
|
||||
@@ -1,11 +1,14 @@
|
||||
# Compound Marketplace
|
||||
|
||||
[](https://github.com/EveryInc/compound-engineering-plugin/actions/workflows/ci.yml)
|
||||
[](https://www.npmjs.com/package/@every-env/compound-plugin)
|
||||
|
||||
A Claude Code plugin marketplace featuring the **Compound Engineering Plugin** — tools that make each unit of engineering work easier than the last.
|
||||
|
||||
## Claude Code Install
|
||||
|
||||
```bash
|
||||
/plugin marketplace add https://github.com/kieranklaassen/compound-engineering-plugin
|
||||
/plugin marketplace add https://github.com/EveryInc/compound-engineering-plugin
|
||||
/plugin install compound-engineering
|
||||
```
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Compounding Engineering - AI-Powered Development Tools for Claude Code</title>
|
||||
<meta content="Your code reviews just got 12 expert opinions in 30 seconds. 27 specialized agents, 19 workflow commands, and 12 skills that make today's work easier than yesterday's." name="description" />
|
||||
<meta content="Your code reviews just got 12 expert opinions in 30 seconds. 28 specialized agents, 24 workflow commands, and 15 skills that make today's work easier than yesterday's." name="description" />
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
@@ -12,7 +12,7 @@
|
||||
<meta property="og:site_name" content="Compounding Engineering" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:title" content="Compounding Engineering - AI Development Tools" />
|
||||
<meta property="og:description" content="Get 12 expert code reviews in 30 seconds. 27 specialized agents that make today's work easier than yesterday's." />
|
||||
<meta property="og:description" content="Get 12 expert code reviews in 30 seconds. 28 specialized agents that make today's work easier than yesterday's." />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Compounding Engineering" />
|
||||
<meta name="twitter:description" content="12 expert code reviews in 30 seconds. Make today's work easier than yesterday's." />
|
||||
@@ -139,7 +139,7 @@
|
||||
<a href="pages/getting-started.html" class="nav-link">Docs</a>
|
||||
</nav>
|
||||
<div class="button-group">
|
||||
<a href="https://github.com/kieranklaassen/every-marketplace" class="button ghost compact hide-on-mobile">
|
||||
<a href="https://github.com/EveryInc/compound-engineering-plugin" class="button ghost compact hide-on-mobile">
|
||||
<div class="fa-brands fa-github icon l"></div>
|
||||
</a>
|
||||
<a href="#install" class="button primary compact">Install</a>
|
||||
@@ -154,14 +154,14 @@
|
||||
<section class="hero-section">
|
||||
<div class="hero-decoration"></div>
|
||||
<div class="heading hero centered">
|
||||
<a href="https://github.com/kieranklaassen/every-marketplace/releases" class="eyebrow">
|
||||
<i class="fa-solid fa-rocket"></i> Version 2.6.0 released!
|
||||
<a href="https://github.com/EveryInc/compound-engineering-plugin/releases" class="eyebrow">
|
||||
<i class="fa-solid fa-rocket"></i> Version 2.28.0 released!
|
||||
</a>
|
||||
<h1 class="balanced" style="margin-bottom: 32px;">
|
||||
Your Code Reviews Just Got 12 Expert Opinions. In 30 Seconds.
|
||||
</h1>
|
||||
<p class="paragraph m secondary balanced" style="margin-bottom: 32px;">
|
||||
Here's what happened when we shipped yesterday: security audit, performance analysis, architectural review, pattern detection, and eight more specialized checks—all running in parallel. No meetings. No waiting. Just answers. That's compounding engineering: 27 specialized agents, 19 workflow commands, and 12 skills that make today's work easier than yesterday's.
|
||||
Here's what happened when we shipped yesterday: security audit, performance analysis, architectural review, pattern detection, and eight more specialized checks—all running in parallel. No meetings. No waiting. Just answers. That's compounding engineering: 28 specialized agents, 24 workflow commands, and 15 skills that make today's work easier than yesterday's.
|
||||
</p>
|
||||
<div class="button-group margin-paragraph centered">
|
||||
<a href="#install" class="button primary">
|
||||
@@ -179,23 +179,23 @@
|
||||
<div class="stats-container">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon"><i class="fa-solid fa-users-gear"></i></div>
|
||||
<div class="stat-number">27</div>
|
||||
<div class="stat-number">28</div>
|
||||
<div class="stat-label">Specialized Agents</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon"><i class="fa-solid fa-terminal"></i></div>
|
||||
<div class="stat-number">19</div>
|
||||
<div class="stat-number">24</div>
|
||||
<div class="stat-label">Slash Commands</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon"><i class="fa-solid fa-wand-magic-sparkles"></i></div>
|
||||
<div class="stat-number">12</div>
|
||||
<div class="stat-number">15</div>
|
||||
<div class="stat-label">Intelligent Skills</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon"><i class="fa-solid fa-server"></i></div>
|
||||
<div class="stat-number">2</div>
|
||||
<div class="stat-label">MCP Servers</div>
|
||||
<div class="stat-number">1</div>
|
||||
<div class="stat-label">MCP Server</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -884,7 +884,7 @@
|
||||
<div class="step-content">
|
||||
<h3>Add the Marketplace</h3>
|
||||
<div class="card-code-block">
|
||||
<pre><code>claude /plugin marketplace add https://github.com/kieranklaassen/every-marketplace</code></pre>
|
||||
<pre><code>claude /plugin marketplace add https://github.com/EveryInc/compound-engineering-plugin</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -996,7 +996,7 @@ skill: gemini-imagegen</code></pre>
|
||||
<i class="fa-solid fa-download"></i> Install Plugin Now
|
||||
<span class="button-arrow">→</span>
|
||||
</a>
|
||||
<a href="https://github.com/kieranklaassen/every-marketplace" class="button tertiary cta-secondary">
|
||||
<a href="https://github.com/EveryInc/compound-engineering-plugin" class="button tertiary cta-secondary">
|
||||
<i class="fa-brands fa-github"></i> View on GitHub
|
||||
</a>
|
||||
</div>
|
||||
@@ -1024,7 +1024,7 @@ skill: gemini-imagegen</code></pre>
|
||||
</div>
|
||||
<div>
|
||||
<div class="link-list">
|
||||
<a href="https://github.com/kieranklaassen/every-marketplace" class="icon-link ui s" target="_blank">
|
||||
<a href="https://github.com/EveryInc/compound-engineering-plugin" class="icon-link ui s" target="_blank">
|
||||
<div class="fa-brands fa-github icon m color-accent"></div>
|
||||
<div class="pseudo-link">GitHub</div>
|
||||
</a>
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
<strong><code>/report-bug</code> command</strong> - New slash command for reporting bugs in the
|
||||
compound-engineering plugin. Provides a structured workflow that gathers bug information
|
||||
through guided questions, collects environment details automatically, and creates a GitHub
|
||||
issue in the kieranklaassen/every-marketplace repository.
|
||||
issue in the EveryInc/compound-engineering-plugin repository.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
<h3>Step 1: Add the Marketplace</h3>
|
||||
<p>Think of the marketplace as an app store. You're adding it to Claude Code's list of places to look for plugins:</p>
|
||||
<div class="card-code-block">
|
||||
<pre><code>claude /plugin marketplace add https://github.com/kieranklaassen/every-marketplace</code></pre>
|
||||
<pre><code>claude /plugin marketplace add https://github.com/EveryInc/compound-engineering-plugin</code></pre>
|
||||
</div>
|
||||
|
||||
<h3>Step 2: Install the Plugin</h3>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@every-env/compound-plugin",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"type": "module",
|
||||
"private": false,
|
||||
"bin": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "compound-engineering",
|
||||
"version": "2.27.0",
|
||||
"description": "AI-powered development tools. 27 agents, 23 commands, 14 skills, 1 MCP server for code review, research, design, and workflow automation.",
|
||||
"version": "2.28.0",
|
||||
"description": "AI-powered development tools. 28 agents, 24 commands, 15 skills, 1 MCP server for code review, research, design, and workflow automation.",
|
||||
"author": {
|
||||
"name": "Kieran Klaassen",
|
||||
"email": "kieran@every.to",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: best-practices-researcher
|
||||
description: "Use this agent when you need to research and gather external best practices, documentation, and examples for any technology, framework, or development practice. This includes finding official documentation, community standards, well-regarded examples from open source projects, and domain-specific conventions. The agent excels at synthesizing information from multiple sources to provide comprehensive guidance on how to implement features or solve problems according to industry standards. <example>Context: User wants to know the best way to structure GitHub issues for their Rails project. user: \"I need to create some GitHub issues for our project. Can you research best practices for writing good issues?\" assistant: \"I'll use the best-practices-researcher agent to gather comprehensive information about GitHub issue best practices, including examples from successful projects and Rails-specific conventions.\" <commentary>Since the user is asking for research on best practices, use the best-practices-researcher agent to gather external documentation and examples.</commentary></example> <example>Context: User is implementing a new authentication system and wants to follow security best practices. user: \"We're adding JWT authentication to our Rails API. What are the current best practices?\" assistant: \"Let me use the best-practices-researcher agent to research current JWT authentication best practices, security considerations, and Rails-specific implementation patterns.\" <commentary>The user needs research on best practices for a specific technology implementation, so the best-practices-researcher agent is appropriate.</commentary></example>"
|
||||
description: "Use this agent when you need to research and gather external best practices, documentation, and examples for any technology, framework, or development practice. This includes finding official documentation, community standards, well-regarded examples from open source projects, and domain-specific conventions. The agent excels at synthesizing information from multiple sources to provide comprehensive guidance on how to implement features or solve problems according to industry standards. <example>Context: User wants to know the best way to structure GitHub issues for their FastAPI project. user: \"I need to create some GitHub issues for our project. Can you research best practices for writing good issues?\" assistant: \"I'll use the best-practices-researcher agent to gather comprehensive information about GitHub issue best practices, including examples from successful projects and FastAPI-specific conventions.\" <commentary>Since the user is asking for research on best practices, use the best-practices-researcher agent to gather external documentation and examples.</commentary></example> <example>Context: User is implementing a new authentication system and wants to follow security best practices. user: \"We're adding JWT authentication to our FastAPI API. What are the current best practices?\" assistant: \"Let me use the best-practices-researcher agent to research current JWT authentication best practices, security considerations, and FastAPI-specific implementation patterns.\" <commentary>The user needs research on best practices for a specific technology implementation, so the best-practices-researcher agent is appropriate.</commentary></example>"
|
||||
model: inherit
|
||||
---
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ Grep: pattern="email" path=docs/solutions/ output_mode=files_with_matches -i=tru
|
||||
**Regardless of Grep results**, always read the critical patterns file:
|
||||
|
||||
```bash
|
||||
Read: docs/solutions/patterns/cora-critical-patterns.md
|
||||
Read: docs/solutions/patterns/critical-patterns.md
|
||||
```
|
||||
|
||||
This file contains must-know patterns that apply across all work - high-severity issues promoted to required reading. Scan for patterns relevant to the current feature/task.
|
||||
@@ -182,7 +182,7 @@ Structure your findings as:
|
||||
- **Relevant Matches**: [Y files]
|
||||
|
||||
### Critical Patterns (Always Check)
|
||||
[Any matching patterns from cora-critical-patterns.md]
|
||||
[Any matching patterns from critical-patterns.md]
|
||||
|
||||
### Relevant Learnings
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ Use the GitHub CLI to create the issue:
|
||||
|
||||
```bash
|
||||
gh issue create \
|
||||
--repo kieranklaassen/every-marketplace \
|
||||
--repo EveryInc/compound-engineering-plugin \
|
||||
--title "[compound-engineering] Bug: [Brief description]" \
|
||||
--body "[Formatted bug report from Step 3]" \
|
||||
--label "bug,compound-engineering"
|
||||
@@ -109,7 +109,7 @@ gh issue create \
|
||||
**Note:** If labels don't exist, create without labels:
|
||||
```bash
|
||||
gh issue create \
|
||||
--repo kieranklaassen/every-marketplace \
|
||||
--repo EveryInc/compound-engineering-plugin \
|
||||
--title "[compound-engineering] Bug: [Brief description]" \
|
||||
--body "[Formatted bug report]"
|
||||
```
|
||||
@@ -126,7 +126,7 @@ After the issue is created:
|
||||
```
|
||||
✅ Bug report submitted successfully!
|
||||
|
||||
Issue: https://github.com/kieranklaassen/every-marketplace/issues/[NUMBER]
|
||||
Issue: https://github.com/EveryInc/compound-engineering-plugin/issues/[NUMBER]
|
||||
Title: [compound-engineering] Bug: [description]
|
||||
|
||||
Thank you for helping improve the compound-engineering plugin!
|
||||
|
||||
@@ -28,7 +28,7 @@ This command launches multiple specialized subagents IN PARALLEL to maximize eff
|
||||
### 1. **Context Analyzer** (Parallel)
|
||||
- Extracts conversation history
|
||||
- Identifies problem type, component, symptoms
|
||||
- Validates against CORA schema
|
||||
- Validates against solution schema
|
||||
- Returns: YAML frontmatter skeleton
|
||||
|
||||
### 2. **Solution Extractor** (Parallel)
|
||||
|
||||
@@ -181,7 +181,7 @@ This command takes a work document (plan, specification, or todo file) and execu
|
||||
- **kieran-rails-reviewer**: Verify Rails conventions (Rails projects)
|
||||
- **performance-oracle**: Check for performance issues
|
||||
- **security-sentinel**: Scan for security vulnerabilities
|
||||
- **cora-test-reviewer**: Review test quality (CORA projects)
|
||||
- **cora-test-reviewer**: Review test quality (Rails projects with comprehensive test coverage)
|
||||
|
||||
Run reviewers in parallel with Task tool:
|
||||
|
||||
@@ -279,7 +279,7 @@ This command takes a work document (plan, specification, or todo file) and execu
|
||||
|
||||
---
|
||||
|
||||
[](https://github.com/kieranklaassen/compound-engineering-plugin) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||
[](https://github.com/EveryInc/compound-engineering-plugin) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
@@ -61,7 +61,7 @@ Extract from conversation history:
|
||||
|
||||
**Required information:**
|
||||
|
||||
- **Module name**: Which CORA module had the problem
|
||||
- **Module name**: Which module or component had the problem
|
||||
- **Symptom**: Observable error/behavior (exact error messages)
|
||||
- **Investigation attempts**: What didn't work and why
|
||||
- **Root cause**: Technical explanation of actual problem
|
||||
@@ -249,7 +249,7 @@ But **NEVER auto-promote**. User decides via decision menu (Option 2).
|
||||
|
||||
**Template for critical pattern addition:**
|
||||
|
||||
When user selects Option 2 (Add to Required Reading), use the template from `assets/critical-pattern-template.md` to structure the pattern entry. Number it sequentially based on existing patterns in `docs/solutions/patterns/cora-critical-patterns.md`.
|
||||
When user selects Option 2 (Add to Required Reading), use the template from `assets/critical-pattern-template.md` to structure the pattern entry. Number it sequentially based on existing patterns in `docs/solutions/patterns/critical-patterns.md`.
|
||||
</step>
|
||||
|
||||
</critical_sequence>
|
||||
@@ -270,7 +270,7 @@ File created:
|
||||
|
||||
What's next?
|
||||
1. Continue workflow (recommended)
|
||||
2. Add to Required Reading - Promote to critical patterns (cora-critical-patterns.md)
|
||||
2. Add to Required Reading - Promote to critical patterns (critical-patterns.md)
|
||||
3. Link related issues - Connect to similar problems
|
||||
4. Add to existing skill - Add to a learning skill (e.g., hotwire-native)
|
||||
5. Create new skill - Extract into new learning skill
|
||||
@@ -295,7 +295,7 @@ User selects this when:
|
||||
Action:
|
||||
1. Extract pattern from the documentation
|
||||
2. Format as ❌ WRONG vs ✅ CORRECT with code examples
|
||||
3. Add to `docs/solutions/patterns/cora-critical-patterns.md`
|
||||
3. Add to `docs/solutions/patterns/critical-patterns.md`
|
||||
4. Add cross-reference back to this doc
|
||||
5. Confirm: "✓ Added to Required Reading. All subagents will see this pattern before code generation."
|
||||
|
||||
@@ -317,7 +317,7 @@ Action:
|
||||
4. Confirm: "✓ Added to [skill-name] skill in [file]"
|
||||
|
||||
Example: For Hotwire Native Tailwind variants solution:
|
||||
- Add to `hotwire-native/references/resources.md` under "CORA-Specific Resources"
|
||||
- Add to `hotwire-native/references/resources.md` under "Project-Specific Resources"
|
||||
- Add to `hotwire-native/references/examples.md` with link to solution doc
|
||||
|
||||
**Option 5: Create new skill**
|
||||
@@ -397,11 +397,11 @@ Documentation is successful when ALL of the following are true:
|
||||
- Present multiple matches
|
||||
- Let user choose: new doc, update existing, or link as duplicate
|
||||
|
||||
**Module not in CORA-MODULES.md:**
|
||||
**Module not in modules documentation:**
|
||||
|
||||
- Warn but don't block
|
||||
- Proceed with documentation
|
||||
- Suggest: "Add [Module] to CORA-MODULES.md if not there"
|
||||
- Suggest: "Add [Module] to modules documentation if not there"
|
||||
|
||||
---
|
||||
|
||||
@@ -488,7 +488,7 @@ File created:
|
||||
|
||||
What's next?
|
||||
1. Continue workflow (recommended)
|
||||
2. Add to Required Reading - Promote to critical patterns (cora-critical-patterns.md)
|
||||
2. Add to Required Reading - Promote to critical patterns (critical-patterns.md)
|
||||
3. Link related issues - Connect to similar problems
|
||||
4. Add to existing skill - Add to a learning skill (e.g., hotwire-native)
|
||||
5. Create new skill - Extract into new learning skill
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Critical Pattern Template
|
||||
|
||||
Use this template when adding a pattern to `docs/solutions/patterns/cora-critical-patterns.md`:
|
||||
Use this template when adding a pattern to `docs/solutions/patterns/critical-patterns.md`:
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
module: [Module name or "CORA" for system-wide]
|
||||
module: [Module name or "System" for system-wide]
|
||||
date: [YYYY-MM-DD]
|
||||
problem_type: [build_error|test_failure|runtime_error|performance_issue|database_issue|security_issue|ui_bug|integration_issue|logic_error]
|
||||
component: [rails_model|rails_controller|rails_view|service_object|background_job|database|frontend_stimulus|hotwire_turbo|email_processing|brief_system|assistant|authentication|payments]
|
||||
@@ -19,7 +19,7 @@ tags: [keyword1, keyword2, keyword3]
|
||||
[1-2 sentence clear description of the issue and what the user experienced]
|
||||
|
||||
## Environment
|
||||
- Module: [Name or "CORA system"]
|
||||
- Module: [Name or "System-wide"]
|
||||
- Rails Version: [e.g., 7.1.2]
|
||||
- Affected Component: [e.g., "Email Processing model", "Brief System service", "Authentication controller"]
|
||||
- Date: [YYYY-MM-DD when this was solved]
|
||||
@@ -78,7 +78,7 @@ tags: [keyword1, keyword2, keyword3]
|
||||
|
||||
## Prevention
|
||||
|
||||
[How to avoid this problem in future CORA development:]
|
||||
[How to avoid this problem in future development:]
|
||||
- [Specific coding practice, check, or pattern to follow]
|
||||
- [What to watch out for]
|
||||
- [How to catch this early]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## Required Fields
|
||||
|
||||
- **module** (string): Module name (e.g., "EmailProcessing") or "CORA" for system-wide issues
|
||||
- **module** (string): Module name (e.g., "EmailProcessing") or "System" for system-wide issues
|
||||
- **date** (string): ISO 8601 date (YYYY-MM-DD)
|
||||
- **problem_type** (enum): One of [build_error, test_failure, runtime_error, performance_issue, database_issue, security_issue, ui_bug, integration_issue, logic_error, developer_experience, workflow_issue, best_practice, documentation_gap]
|
||||
- **component** (enum): One of [rails_model, rails_controller, rails_view, service_object, background_job, database, frontend_stimulus, hotwire_turbo, email_processing, brief_system, assistant, authentication, payments, development_workflow, testing_framework, documentation, tooling]
|
||||
|
||||
@@ -175,7 +175,9 @@ function resolveOutputRoot(value: unknown): string {
|
||||
const expanded = expandHome(String(value).trim())
|
||||
return path.resolve(expanded)
|
||||
}
|
||||
return path.join(os.homedir(), ".opencode")
|
||||
// OpenCode global config lives at ~/.config/opencode per XDG spec
|
||||
// See: https://opencode.ai/docs/config/
|
||||
return path.join(os.homedir(), ".config", "opencode")
|
||||
}
|
||||
|
||||
async function resolveGitHubPluginPath(pluginName: string): Promise<ResolvedPluginPath> {
|
||||
|
||||
@@ -73,19 +73,76 @@ function convertCommandSkill(command: ClaudeCommand, usedNames: Set<string>): Co
|
||||
if (command.allowedTools && command.allowedTools.length > 0) {
|
||||
sections.push(`## Allowed tools\n${command.allowedTools.map((tool) => `- ${tool}`).join("\n")}`)
|
||||
}
|
||||
sections.push(command.body.trim())
|
||||
// Transform Task agent calls to Codex skill references
|
||||
const transformedBody = transformTaskCalls(command.body.trim())
|
||||
sections.push(transformedBody)
|
||||
const body = sections.filter(Boolean).join("\n\n").trim()
|
||||
const content = formatFrontmatter(frontmatter, body.length > 0 ? body : command.body)
|
||||
return { name, content }
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform Claude Code content to Codex-compatible content.
|
||||
*
|
||||
* Handles multiple syntax differences:
|
||||
* 1. Task agent calls: Task agent-name(args) → Use the $agent-name skill to: args
|
||||
* 2. Slash commands: /command-name → /prompts:command-name
|
||||
* 3. Agent references: @agent-name → $agent-name skill
|
||||
*
|
||||
* This bridges the gap since Claude Code and Codex have different syntax
|
||||
* for invoking commands, agents, and skills.
|
||||
*/
|
||||
function transformContentForCodex(body: string): string {
|
||||
let result = body
|
||||
|
||||
// 1. Transform Task agent calls
|
||||
// Match: Task repo-research-analyst(feature_description)
|
||||
// Match: - Task learnings-researcher(args)
|
||||
const taskPattern = /^(\s*-?\s*)Task\s+([a-z][a-z0-9-]*)\(([^)]+)\)/gm
|
||||
result = result.replace(taskPattern, (_match, prefix: string, agentName: string, args: string) => {
|
||||
const skillName = normalizeName(agentName)
|
||||
const trimmedArgs = args.trim()
|
||||
return `${prefix}Use the $${skillName} skill to: ${trimmedArgs}`
|
||||
})
|
||||
|
||||
// 2. Transform slash command references
|
||||
// Match: /command-name or /workflows:command but NOT /path/to/file or URLs
|
||||
// Look for slash commands in contexts like "Run /command", "use /command", etc.
|
||||
// Avoid matching file paths (contain multiple slashes) or URLs (contain ://)
|
||||
const slashCommandPattern = /(?<![:\w])\/([a-z][a-z0-9_:-]*?)(?=[\s,."')\]}`]|$)/gi
|
||||
result = result.replace(slashCommandPattern, (match, commandName: string) => {
|
||||
// Skip if it looks like a file path (contains /)
|
||||
if (commandName.includes('/')) return match
|
||||
// Skip common non-command patterns
|
||||
if (['dev', 'tmp', 'etc', 'usr', 'var', 'bin', 'home'].includes(commandName)) return match
|
||||
// Transform to Codex prompt syntax
|
||||
const normalizedName = normalizeName(commandName)
|
||||
return `/prompts:${normalizedName}`
|
||||
})
|
||||
|
||||
// 3. Transform @agent-name references
|
||||
// Match: @agent-name in text (not emails)
|
||||
const agentRefPattern = /@([a-z][a-z0-9-]*-(?:agent|reviewer|researcher|analyst|specialist|oracle|sentinel|guardian|strategist))/gi
|
||||
result = result.replace(agentRefPattern, (_match, agentName: string) => {
|
||||
const skillName = normalizeName(agentName)
|
||||
return `$${skillName} skill`
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Alias for backward compatibility
|
||||
const transformTaskCalls = transformContentForCodex
|
||||
|
||||
function renderPrompt(command: ClaudeCommand, skillName: string): string {
|
||||
const frontmatter: Record<string, unknown> = {
|
||||
description: command.description,
|
||||
"argument-hint": command.argumentHint,
|
||||
}
|
||||
const instructions = `Use the $${skillName} skill for this command and follow its instructions.`
|
||||
const body = [instructions, "", command.body].join("\n").trim()
|
||||
// Transform Task calls in prompt body too (not just skill body)
|
||||
const transformedBody = transformTaskCalls(command.body)
|
||||
const body = [instructions, "", transformedBody].join("\n").trim()
|
||||
return formatFrontmatter(frontmatter, body)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,10 @@ export async function writeOpenCodeBundle(outputRoot: string, bundle: OpenCodeBu
|
||||
}
|
||||
|
||||
function resolveOpenCodePaths(outputRoot: string) {
|
||||
if (path.basename(outputRoot) === ".opencode") {
|
||||
const base = path.basename(outputRoot)
|
||||
// Global install: ~/.config/opencode (basename is "opencode")
|
||||
// Project install: .opencode (basename is ".opencode")
|
||||
if (base === "opencode" || base === ".opencode") {
|
||||
return {
|
||||
root: outputRoot,
|
||||
configPath: path.join(outputRoot, "opencode.json"),
|
||||
@@ -38,6 +41,7 @@ function resolveOpenCodePaths(outputRoot: string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Custom output directory - nest under .opencode subdirectory
|
||||
return {
|
||||
root: outputRoot,
|
||||
configPath: path.join(outputRoot, "opencode.json"),
|
||||
|
||||
@@ -63,7 +63,7 @@ describe("CLI", () => {
|
||||
expect(await exists(path.join(tempRoot, ".opencode", "plugins", "converted-hooks.ts"))).toBe(true)
|
||||
})
|
||||
|
||||
test("install defaults output to ~/.opencode", async () => {
|
||||
test("install defaults output to ~/.config/opencode", async () => {
|
||||
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "cli-local-default-"))
|
||||
const fixtureRoot = path.join(import.meta.dir, "fixtures", "sample-plugin")
|
||||
|
||||
@@ -95,8 +95,9 @@ describe("CLI", () => {
|
||||
}
|
||||
|
||||
expect(stdout).toContain("Installed compound-engineering")
|
||||
expect(await exists(path.join(tempRoot, ".opencode", "opencode.json"))).toBe(true)
|
||||
expect(await exists(path.join(tempRoot, ".opencode", "agents", "repo-research-analyst.md"))).toBe(true)
|
||||
// OpenCode global config lives at ~/.config/opencode per XDG spec
|
||||
expect(await exists(path.join(tempRoot, ".config", "opencode", "opencode.json"))).toBe(true)
|
||||
expect(await exists(path.join(tempRoot, ".config", "opencode", "agents", "repo-research-analyst.md"))).toBe(true)
|
||||
})
|
||||
|
||||
test("list returns plugins in a temp workspace", async () => {
|
||||
@@ -174,8 +175,9 @@ describe("CLI", () => {
|
||||
}
|
||||
|
||||
expect(stdout).toContain("Installed compound-engineering")
|
||||
expect(await exists(path.join(tempRoot, ".opencode", "opencode.json"))).toBe(true)
|
||||
expect(await exists(path.join(tempRoot, ".opencode", "agents", "repo-research-analyst.md"))).toBe(true)
|
||||
// OpenCode global config lives at ~/.config/opencode per XDG spec
|
||||
expect(await exists(path.join(tempRoot, ".config", "opencode", "opencode.json"))).toBe(true)
|
||||
expect(await exists(path.join(tempRoot, ".config", "opencode", "agents", "repo-research-analyst.md"))).toBe(true)
|
||||
})
|
||||
|
||||
test("convert writes OpenCode output", async () => {
|
||||
|
||||
@@ -89,6 +89,89 @@ describe("convertClaudeToCodex", () => {
|
||||
expect(bundle.mcpServers?.local?.args).toEqual(["hello"])
|
||||
})
|
||||
|
||||
test("transforms Task agent calls to skill references", () => {
|
||||
const plugin: ClaudePlugin = {
|
||||
...fixturePlugin,
|
||||
commands: [
|
||||
{
|
||||
name: "plan",
|
||||
description: "Planning with agents",
|
||||
body: `Run these agents in parallel:
|
||||
|
||||
- Task repo-research-analyst(feature_description)
|
||||
- Task learnings-researcher(feature_description)
|
||||
|
||||
Then consolidate findings.
|
||||
|
||||
Task best-practices-researcher(topic)`,
|
||||
sourcePath: "/tmp/plugin/commands/plan.md",
|
||||
},
|
||||
],
|
||||
agents: [],
|
||||
skills: [],
|
||||
}
|
||||
|
||||
const bundle = convertClaudeToCodex(plugin, {
|
||||
agentMode: "subagent",
|
||||
inferTemperature: false,
|
||||
permissions: "none",
|
||||
})
|
||||
|
||||
const commandSkill = bundle.generatedSkills.find((s) => s.name === "plan")
|
||||
expect(commandSkill).toBeDefined()
|
||||
const parsed = parseFrontmatter(commandSkill!.content)
|
||||
|
||||
// Task calls should be transformed to skill references
|
||||
expect(parsed.body).toContain("Use the $repo-research-analyst skill to: feature_description")
|
||||
expect(parsed.body).toContain("Use the $learnings-researcher skill to: feature_description")
|
||||
expect(parsed.body).toContain("Use the $best-practices-researcher skill to: topic")
|
||||
|
||||
// Original Task syntax should not remain
|
||||
expect(parsed.body).not.toContain("Task repo-research-analyst")
|
||||
expect(parsed.body).not.toContain("Task learnings-researcher")
|
||||
})
|
||||
|
||||
test("transforms slash commands to prompts syntax", () => {
|
||||
const plugin: ClaudePlugin = {
|
||||
...fixturePlugin,
|
||||
commands: [
|
||||
{
|
||||
name: "plan",
|
||||
description: "Planning with commands",
|
||||
body: `After planning, you can:
|
||||
|
||||
1. Run /deepen-plan to enhance
|
||||
2. Run /plan_review for feedback
|
||||
3. Start /workflows:work to implement
|
||||
|
||||
Don't confuse with file paths like /tmp/output.md or /dev/null.`,
|
||||
sourcePath: "/tmp/plugin/commands/plan.md",
|
||||
},
|
||||
],
|
||||
agents: [],
|
||||
skills: [],
|
||||
}
|
||||
|
||||
const bundle = convertClaudeToCodex(plugin, {
|
||||
agentMode: "subagent",
|
||||
inferTemperature: false,
|
||||
permissions: "none",
|
||||
})
|
||||
|
||||
const commandSkill = bundle.generatedSkills.find((s) => s.name === "plan")
|
||||
expect(commandSkill).toBeDefined()
|
||||
const parsed = parseFrontmatter(commandSkill!.content)
|
||||
|
||||
// Slash commands should be transformed to /prompts: syntax
|
||||
expect(parsed.body).toContain("/prompts:deepen-plan")
|
||||
expect(parsed.body).toContain("/prompts:plan_review")
|
||||
expect(parsed.body).toContain("/prompts:workflows-work")
|
||||
|
||||
// File paths should NOT be transformed
|
||||
expect(parsed.body).toContain("/tmp/output.md")
|
||||
expect(parsed.body).toContain("/dev/null")
|
||||
})
|
||||
|
||||
test("truncates generated skill descriptions to Codex limits and single line", () => {
|
||||
const longDescription = `Line one\nLine two ${"a".repeat(2000)}`
|
||||
const plugin: ClaudePlugin = {
|
||||
|
||||
@@ -59,4 +59,29 @@ describe("writeOpenCodeBundle", () => {
|
||||
expect(await exists(path.join(outputRoot, "skills", "skill-one", "SKILL.md"))).toBe(true)
|
||||
expect(await exists(path.join(outputRoot, ".opencode"))).toBe(false)
|
||||
})
|
||||
|
||||
test("writes directly into ~/.config/opencode style output root", async () => {
|
||||
// Simulates the global install path: ~/.config/opencode
|
||||
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "config-opencode-"))
|
||||
const outputRoot = path.join(tempRoot, ".config", "opencode")
|
||||
const bundle: OpenCodeBundle = {
|
||||
config: { $schema: "https://opencode.ai/config.json" },
|
||||
agents: [{ name: "agent-one", content: "Agent content" }],
|
||||
plugins: [],
|
||||
skillDirs: [
|
||||
{
|
||||
name: "skill-one",
|
||||
sourceDir: path.join(import.meta.dir, "fixtures", "sample-plugin", "skills", "skill-one"),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
await writeOpenCodeBundle(outputRoot, bundle)
|
||||
|
||||
// Should write directly, not nested under .opencode
|
||||
expect(await exists(path.join(outputRoot, "opencode.json"))).toBe(true)
|
||||
expect(await exists(path.join(outputRoot, "agents", "agent-one.md"))).toBe(true)
|
||||
expect(await exists(path.join(outputRoot, "skills", "skill-one", "SKILL.md"))).toBe(true)
|
||||
expect(await exists(path.join(outputRoot, ".opencode"))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user