docs: refresh stale target list and release component references (#339)
This commit is contained in:
@@ -13,21 +13,22 @@ root_cause: architectural_pattern
|
|||||||
|
|
||||||
## Problem
|
## Problem
|
||||||
|
|
||||||
When adding support for a new AI platform (e.g., Devin, Cursor, Copilot), the converter CLI architecture requires consistent implementation across types, converters, writers, CLI integration, and tests. Without documented patterns and learnings, new targets take longer to implement and risk architectural inconsistency.
|
When adding support for a new AI platform (e.g., Copilot, Windsurf, Qwen), the converter CLI architecture requires consistent implementation across types, converters, writers, CLI integration, and tests. Without documented patterns and learnings, new targets take longer to implement and risk architectural inconsistency.
|
||||||
|
|
||||||
## Solution
|
## Solution
|
||||||
|
|
||||||
The compound-engineering-plugin uses a proven **6-phase target provider pattern** that has been successfully applied to 8 targets:
|
The compound-engineering-plugin uses a proven **6-phase target provider pattern** that has been successfully applied to 10 targets:
|
||||||
|
|
||||||
1. **OpenCode** (primary target, reference implementation)
|
1. **OpenCode** (primary target, reference implementation)
|
||||||
2. **Codex** (second target, established pattern)
|
2. **Codex** (second target, established pattern)
|
||||||
3. **Droid/Factory** (workflow/agent conversion)
|
3. **Droid/Factory** (workflow/agent conversion)
|
||||||
4. **Pi** (MCPorter ecosystem)
|
4. **Pi** (MCPorter ecosystem)
|
||||||
5. **Gemini CLI** (content transformation patterns)
|
5. **Gemini CLI** (content transformation patterns)
|
||||||
6. **Cursor** (command flattening, rule formats)
|
6. **Copilot** (GitHub native, MCP prefixing)
|
||||||
7. **Copilot** (GitHub native, MCP prefixing)
|
7. **Kiro** (limited MCP support)
|
||||||
8. **Kiro** (limited MCP support)
|
8. **Windsurf** (rules-based format)
|
||||||
9. **Devin** (playbook conversion, knowledge entries)
|
9. **OpenClaw** (open agent format)
|
||||||
|
10. **Qwen** (Qwen agent format)
|
||||||
|
|
||||||
Each implementation follows this architecture precisely, ensuring consistency and maintainability.
|
Each implementation follows this architecture precisely, ensuring consistency and maintainability.
|
||||||
|
|
||||||
@@ -63,14 +64,14 @@ export type {TargetName}Agent = {
|
|||||||
**Key Learnings:**
|
**Key Learnings:**
|
||||||
|
|
||||||
- Always include a `content` field (full file text) rather than decomposed fields — it's simpler and matches how files are written
|
- Always include a `content` field (full file text) rather than decomposed fields — it's simpler and matches how files are written
|
||||||
- Use intermediate types for complex sections (e.g., `DevinPlaybookSections` in Devin converter) to make section building independently testable
|
- Use intermediate types for complex sections to make section building independently testable
|
||||||
- Avoid target-specific fields in the base bundle unless essential — aim for shared structure across targets
|
- Avoid target-specific fields in the base bundle unless essential — aim for shared structure across targets
|
||||||
- Include a `category` field if the target has file-type variants (agents vs. commands vs. rules)
|
- Include a `category` field if the target has file-type variants (agents vs. commands vs. rules)
|
||||||
|
|
||||||
**Reference Implementations:**
|
**Reference Implementations:**
|
||||||
- OpenCode: `src/types/opencode.ts` (command + agent split)
|
- OpenCode: `src/types/opencode.ts` (command + agent split)
|
||||||
- Devin: `src/types/devin.ts` (playbooks + knowledge entries)
|
|
||||||
- Copilot: `src/types/copilot.ts` (agents + skills + MCP)
|
- Copilot: `src/types/copilot.ts` (agents + skills + MCP)
|
||||||
|
- Windsurf: `src/types/windsurf.ts` (rules-based format)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ export function transformContentFor{Target}(body: string): string {
|
|||||||
|
|
||||||
**Deduplication Pattern (`uniqueName`):**
|
**Deduplication Pattern (`uniqueName`):**
|
||||||
|
|
||||||
Used when target has flat namespaces (Cursor, Copilot, Devin) or when name collisions occur:
|
Used when target has flat namespaces (Copilot, Windsurf) or when name collisions occur:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function uniqueName(base: string, used: Set<string>): string {
|
function uniqueName(base: string, used: Set<string>): string {
|
||||||
@@ -197,7 +198,7 @@ function flattenCommandName(name: string): string {
|
|||||||
|
|
||||||
**Key Learnings:**
|
**Key Learnings:**
|
||||||
|
|
||||||
1. **Pre-scan for cross-references** — If target requires reference names (macros, URIs, IDs), build a map before conversion. Example: Devin needs macro names like `agent_kieran_rails_reviewer`, so pre-scan builds the map.
|
1. **Pre-scan for cross-references** — If target requires reference names (macros, URIs, IDs), build a map before conversion to avoid name collisions and enable deduplication.
|
||||||
|
|
||||||
2. **Content transformation is fragile** — Test extensively. Patterns that work for slash commands might false-match on file paths. Use negative lookahead to skip `/etc`, `/usr`, `/var`, etc.
|
2. **Content transformation is fragile** — Test extensively. Patterns that work for slash commands might false-match on file paths. Use negative lookahead to skip `/etc`, `/usr`, `/var`, etc.
|
||||||
|
|
||||||
@@ -208,15 +209,15 @@ function flattenCommandName(name: string): string {
|
|||||||
5. **MCP servers need target-specific handling:**
|
5. **MCP servers need target-specific handling:**
|
||||||
- **OpenCode:** Merge into `opencode.json` (preserve user keys)
|
- **OpenCode:** Merge into `opencode.json` (preserve user keys)
|
||||||
- **Copilot:** Prefix env vars with `COPILOT_MCP_`, emit JSON
|
- **Copilot:** Prefix env vars with `COPILOT_MCP_`, emit JSON
|
||||||
- **Devin:** Write setup instructions file (config is via web UI)
|
- **Windsurf:** Write MCP config in target-specific format
|
||||||
- **Cursor:** Pass through as-is
|
- **Kiro:** Limited MCP support, check compatibility
|
||||||
|
|
||||||
6. **Warn on unsupported features** — Hooks, Gemini extensions, Kiro-incompatible MCP types. Emit to stderr and continue conversion.
|
6. **Warn on unsupported features** — Hooks, Gemini extensions, Kiro-incompatible MCP types. Emit to stderr and continue conversion.
|
||||||
|
|
||||||
**Reference Implementations:**
|
**Reference Implementations:**
|
||||||
- OpenCode: `src/converters/claude-to-opencode.ts` (most comprehensive)
|
- OpenCode: `src/converters/claude-to-opencode.ts` (most comprehensive)
|
||||||
- Devin: `src/converters/claude-to-devin.ts` (content transformation + cross-references)
|
|
||||||
- Copilot: `src/converters/claude-to-copilot.ts` (MCP prefixing pattern)
|
- Copilot: `src/converters/claude-to-copilot.ts` (MCP prefixing pattern)
|
||||||
|
- Windsurf: `src/converters/claude-to-windsurf.ts` (rules-based conversion)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -328,8 +329,7 @@ export async function backupFile(filePath: string): Promise<string | null> {
|
|||||||
|
|
||||||
5. **File extensions matter** — Match target conventions exactly:
|
5. **File extensions matter** — Match target conventions exactly:
|
||||||
- Copilot: `.agent.md` (note the dot)
|
- Copilot: `.agent.md` (note the dot)
|
||||||
- Cursor: `.mdc` for rules
|
- Windsurf: `.md` for rules
|
||||||
- Devin: `.devin.md` for playbooks
|
|
||||||
- OpenCode: `.md` for commands
|
- OpenCode: `.md` for commands
|
||||||
|
|
||||||
6. **Permissions for sensitive files** — MCP config with API keys should use `0o600`:
|
6. **Permissions for sensitive files** — MCP config with API keys should use `0o600`:
|
||||||
@@ -340,7 +340,7 @@ export async function backupFile(filePath: string): Promise<string | null> {
|
|||||||
**Reference Implementations:**
|
**Reference Implementations:**
|
||||||
- Droid: `src/targets/droid.ts` (simpler pattern, good for learning)
|
- Droid: `src/targets/droid.ts` (simpler pattern, good for learning)
|
||||||
- Copilot: `src/targets/copilot.ts` (double-nesting pattern)
|
- Copilot: `src/targets/copilot.ts` (double-nesting pattern)
|
||||||
- Devin: `src/targets/devin.ts` (setup instructions file)
|
- Windsurf: `src/targets/windsurf.ts` (rules-based output)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -377,7 +377,7 @@ if (targetName === "{target}") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update --to flag description
|
// Update --to flag description
|
||||||
const toDescription = "Target format (opencode | codex | droid | cursor | copilot | kiro | {target})"
|
const toDescription = "Target format (opencode | codex | droid | cursor | pi | copilot | gemini | kiro | windsurf | openclaw | qwen | all)"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -427,7 +427,7 @@ export async function syncTo{Target}(outputRoot: string): Promise<void> {
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Add to validTargets array
|
// Add to validTargets array
|
||||||
const validTargets = ["opencode", "codex", "droid", "cursor", "pi", "{target}"] as const
|
const validTargets = ["opencode", "codex", "droid", "pi", "copilot", "gemini", "kiro", "windsurf", "openclaw", "qwen", "{target}"] as const
|
||||||
|
|
||||||
// In resolveOutputRoot()
|
// In resolveOutputRoot()
|
||||||
case "{target}":
|
case "{target}":
|
||||||
@@ -614,7 +614,7 @@ Add to supported targets list and include usage examples.
|
|||||||
|
|
||||||
| Pitfall | Solution |
|
| Pitfall | Solution |
|
||||||
|---------|----------|
|
|---------|----------|
|
||||||
| **Double-nesting** (`.cursor/.cursor/`) | Check `path.basename(outputRoot)` before nesting |
|
| **Double-nesting** (`.copilot/.copilot/`) | Check `path.basename(outputRoot)` before nesting |
|
||||||
| **Inconsistent name normalization** | Use single `normalizeName()` function everywhere |
|
| **Inconsistent name normalization** | Use single `normalizeName()` function everywhere |
|
||||||
| **Fragile content transformation** | Test regex patterns against edge cases (file paths, URLs) |
|
| **Fragile content transformation** | Test regex patterns against edge cases (file paths, URLs) |
|
||||||
| **Heuristic section extraction fails** | Use structural mapping (description → Overview, body → Procedure) instead |
|
| **Heuristic section extraction fails** | Use structural mapping (description → Overview, body → Procedure) instead |
|
||||||
@@ -667,7 +667,7 @@ Use this checklist when adding a new target provider:
|
|||||||
|
|
||||||
1. **Droid** (`src/targets/droid.ts`, `src/converters/claude-to-droid.ts`) — Simplest pattern, good learning baseline
|
1. **Droid** (`src/targets/droid.ts`, `src/converters/claude-to-droid.ts`) — Simplest pattern, good learning baseline
|
||||||
2. **Copilot** (`src/targets/copilot.ts`, `src/converters/claude-to-copilot.ts`) — MCP prefixing, double-nesting guard
|
2. **Copilot** (`src/targets/copilot.ts`, `src/converters/claude-to-copilot.ts`) — MCP prefixing, double-nesting guard
|
||||||
3. **Devin** (`src/converters/claude-to-devin.ts`) — Content transformation, cross-references, intermediate types
|
3. **Windsurf** (`src/targets/windsurf.ts`, `src/converters/claude-to-windsurf.ts`) — Rules-based conversion
|
||||||
4. **OpenCode** (`src/converters/claude-to-opencode.ts`) — Most comprehensive, handles command structure and config merging
|
4. **OpenCode** (`src/converters/claude-to-opencode.ts`) — Most comprehensive, handles command structure and config merging
|
||||||
|
|
||||||
### Key Utilities
|
### Key Utilities
|
||||||
@@ -678,7 +678,6 @@ Use this checklist when adding a new target provider:
|
|||||||
|
|
||||||
### Existing Tests
|
### Existing Tests
|
||||||
|
|
||||||
- `tests/cursor-converter.test.ts` — Comprehensive converter tests
|
|
||||||
- `tests/copilot-writer.test.ts` — Writer tests with temp directories
|
- `tests/copilot-writer.test.ts` — Writer tests with temp directories
|
||||||
- `tests/sync-copilot.test.ts` — Sync pattern with symlinks and config merge
|
- `tests/sync-copilot.test.ts` — Sync pattern with symlinks and config merge
|
||||||
|
|
||||||
|
|||||||
@@ -46,11 +46,12 @@ Move the repo to a manual `release-please` model with one standing release PR an
|
|||||||
|
|
||||||
Key decisions:
|
Key decisions:
|
||||||
|
|
||||||
- Use `release-please` manifest mode for four release components:
|
- Use `release-please` manifest mode for five release components:
|
||||||
- `cli`
|
- `cli`
|
||||||
- `compound-engineering`
|
- `compound-engineering`
|
||||||
- `coding-tutor`
|
- `coding-tutor`
|
||||||
- `marketplace`
|
- `marketplace` (Claude marketplace, `.claude-plugin/`)
|
||||||
|
- `cursor-marketplace` (Cursor marketplace, `.cursor-plugin/`)
|
||||||
- Keep release timing manual: the actual release happens when the generated release PR is merged.
|
- Keep release timing manual: the actual release happens when the generated release PR is merged.
|
||||||
- Keep release PR maintenance automatic on pushes to `main`.
|
- Keep release PR maintenance automatic on pushes to `main`.
|
||||||
- Use GitHub release PRs and GitHub Releases as the canonical release-notes surface for new releases.
|
- Use GitHub release PRs and GitHub Releases as the canonical release-notes surface for new releases.
|
||||||
@@ -101,6 +102,7 @@ After the migration:
|
|||||||
- `plugins/compound-engineering/**` => `compound-engineering`
|
- `plugins/compound-engineering/**` => `compound-engineering`
|
||||||
- `plugins/coding-tutor/**` => `coding-tutor`
|
- `plugins/coding-tutor/**` => `coding-tutor`
|
||||||
- `.claude-plugin/marketplace.json` => `marketplace`
|
- `.claude-plugin/marketplace.json` => `marketplace`
|
||||||
|
- `.cursor-plugin/marketplace.json` => `cursor-marketplace`
|
||||||
- Optional title scopes are advisory only.
|
- Optional title scopes are advisory only.
|
||||||
|
|
||||||
This keeps titles simple while still letting the release system decide the correct component bump.
|
This keeps titles simple while still letting the release system decide the correct component bump.
|
||||||
@@ -147,6 +149,7 @@ This keeps titles simple while still letting the release system decide the corre
|
|||||||
- `compound-engineering-vX.Y.Z`
|
- `compound-engineering-vX.Y.Z`
|
||||||
- `coding-tutor-vX.Y.Z`
|
- `coding-tutor-vX.Y.Z`
|
||||||
- `marketplace-vX.Y.Z`
|
- `marketplace-vX.Y.Z`
|
||||||
|
- `cursor-marketplace-vX.Y.Z`
|
||||||
- Root `CHANGELOG.md` is only a pointer to GitHub Releases and is not the canonical source for new releases.
|
- Root `CHANGELOG.md` is only a pointer to GitHub Releases and is not the canonical source for new releases.
|
||||||
|
|
||||||
## Key Files
|
## Key Files
|
||||||
|
|||||||
Reference in New Issue
Block a user