@every-env/compound-plugin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/.claude-plugin/marketplace.json +37 -0
  2. package/.github/workflows/deploy-docs.yml +39 -0
  3. package/AGENTS.md +48 -0
  4. package/CLAUDE.md +380 -0
  5. package/LICENSE +21 -0
  6. package/README.md +65 -0
  7. package/bun.lock +30 -0
  8. package/docs/css/docs.css +675 -0
  9. package/docs/css/style.css +2886 -0
  10. package/docs/index.html +1046 -0
  11. package/docs/js/main.js +225 -0
  12. package/docs/pages/agents.html +649 -0
  13. package/docs/pages/changelog.html +495 -0
  14. package/docs/pages/commands.html +523 -0
  15. package/docs/pages/getting-started.html +582 -0
  16. package/docs/pages/mcp-servers.html +409 -0
  17. package/docs/pages/skills.html +611 -0
  18. package/docs/solutions/plugin-versioning-requirements.md +77 -0
  19. package/docs/specs/claude-code.md +67 -0
  20. package/docs/specs/codex.md +59 -0
  21. package/docs/specs/opencode.md +57 -0
  22. package/package.json +26 -0
  23. package/plans/grow-your-own-garden-plugin-architecture.md +102 -0
  24. package/plans/landing-page-launchkit-refresh.md +279 -0
  25. package/plugins/coding-tutor/.claude-plugin/plugin.json +9 -0
  26. package/plugins/coding-tutor/README.md +37 -0
  27. package/plugins/coding-tutor/commands/quiz-me.md +1 -0
  28. package/plugins/coding-tutor/commands/sync-tutorials.md +25 -0
  29. package/plugins/coding-tutor/commands/teach-me.md +1 -0
  30. package/plugins/coding-tutor/skills/coding-tutor/SKILL.md +214 -0
  31. package/plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py +207 -0
  32. package/plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py +193 -0
  33. package/plugins/coding-tutor/skills/coding-tutor/scripts/quiz_priority.py +190 -0
  34. package/plugins/coding-tutor/skills/coding-tutor/scripts/setup_tutorials.py +118 -0
  35. package/plugins/compound-engineering/.claude-plugin/plugin.json +33 -0
  36. package/plugins/compound-engineering/CHANGELOG.md +393 -0
  37. package/plugins/compound-engineering/CLAUDE.md +90 -0
  38. package/plugins/compound-engineering/LICENSE +21 -0
  39. package/plugins/compound-engineering/README.md +219 -0
  40. package/plugins/compound-engineering/agents/design/design-implementation-reviewer.md +94 -0
  41. package/plugins/compound-engineering/agents/design/design-iterator.md +197 -0
  42. package/plugins/compound-engineering/agents/design/figma-design-sync.md +172 -0
  43. package/plugins/compound-engineering/agents/docs/ankane-readme-writer.md +50 -0
  44. package/plugins/compound-engineering/agents/research/best-practices-researcher.md +100 -0
  45. package/plugins/compound-engineering/agents/research/framework-docs-researcher.md +83 -0
  46. package/plugins/compound-engineering/agents/research/git-history-analyzer.md +42 -0
  47. package/plugins/compound-engineering/agents/research/repo-research-analyst.md +113 -0
  48. package/plugins/compound-engineering/agents/review/agent-native-reviewer.md +246 -0
  49. package/plugins/compound-engineering/agents/review/architecture-strategist.md +52 -0
  50. package/plugins/compound-engineering/agents/review/code-simplicity-reviewer.md +85 -0
  51. package/plugins/compound-engineering/agents/review/data-integrity-guardian.md +70 -0
  52. package/plugins/compound-engineering/agents/review/data-migration-expert.md +97 -0
  53. package/plugins/compound-engineering/agents/review/deployment-verification-agent.md +159 -0
  54. package/plugins/compound-engineering/agents/review/dhh-rails-reviewer.md +45 -0
  55. package/plugins/compound-engineering/agents/review/julik-frontend-races-reviewer.md +222 -0
  56. package/plugins/compound-engineering/agents/review/kieran-python-reviewer.md +104 -0
  57. package/plugins/compound-engineering/agents/review/kieran-rails-reviewer.md +86 -0
  58. package/plugins/compound-engineering/agents/review/kieran-typescript-reviewer.md +95 -0
  59. package/plugins/compound-engineering/agents/review/pattern-recognition-specialist.md +57 -0
  60. package/plugins/compound-engineering/agents/review/performance-oracle.md +110 -0
  61. package/plugins/compound-engineering/agents/review/security-sentinel.md +93 -0
  62. package/plugins/compound-engineering/agents/workflow/bug-reproduction-validator.md +67 -0
  63. package/plugins/compound-engineering/agents/workflow/every-style-editor.md +64 -0
  64. package/plugins/compound-engineering/agents/workflow/lint.md +16 -0
  65. package/plugins/compound-engineering/agents/workflow/pr-comment-resolver.md +69 -0
  66. package/plugins/compound-engineering/agents/workflow/spec-flow-analyzer.md +113 -0
  67. package/plugins/compound-engineering/commands/agent-native-audit.md +277 -0
  68. package/plugins/compound-engineering/commands/changelog.md +137 -0
  69. package/plugins/compound-engineering/commands/create-agent-skill.md +8 -0
  70. package/plugins/compound-engineering/commands/deepen-plan.md +546 -0
  71. package/plugins/compound-engineering/commands/deploy-docs.md +112 -0
  72. package/plugins/compound-engineering/commands/feature-video.md +342 -0
  73. package/plugins/compound-engineering/commands/generate_command.md +162 -0
  74. package/plugins/compound-engineering/commands/heal-skill.md +142 -0
  75. package/plugins/compound-engineering/commands/lfg.md +19 -0
  76. package/plugins/compound-engineering/commands/plan_review.md +7 -0
  77. package/plugins/compound-engineering/commands/release-docs.md +211 -0
  78. package/plugins/compound-engineering/commands/report-bug.md +150 -0
  79. package/plugins/compound-engineering/commands/reproduce-bug.md +99 -0
  80. package/plugins/compound-engineering/commands/resolve_parallel.md +34 -0
  81. package/plugins/compound-engineering/commands/resolve_pr_parallel.md +49 -0
  82. package/plugins/compound-engineering/commands/resolve_todo_parallel.md +35 -0
  83. package/plugins/compound-engineering/commands/test-browser.md +339 -0
  84. package/plugins/compound-engineering/commands/triage.md +310 -0
  85. package/plugins/compound-engineering/commands/workflows/compound.md +202 -0
  86. package/plugins/compound-engineering/commands/workflows/plan.md +466 -0
  87. package/plugins/compound-engineering/commands/workflows/review.md +514 -0
  88. package/plugins/compound-engineering/commands/workflows/work.md +363 -0
  89. package/plugins/compound-engineering/commands/xcode-test.md +331 -0
  90. package/plugins/compound-engineering/skills/agent-browser/SKILL.md +223 -0
  91. package/plugins/compound-engineering/skills/agent-native-architecture/SKILL.md +435 -0
  92. package/plugins/compound-engineering/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
  93. package/plugins/compound-engineering/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
  94. package/plugins/compound-engineering/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
  95. package/plugins/compound-engineering/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
  96. package/plugins/compound-engineering/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
  97. package/plugins/compound-engineering/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
  98. package/plugins/compound-engineering/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
  99. package/plugins/compound-engineering/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
  100. package/plugins/compound-engineering/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
  101. package/plugins/compound-engineering/skills/agent-native-architecture/references/product-implications.md +443 -0
  102. package/plugins/compound-engineering/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
  103. package/plugins/compound-engineering/skills/agent-native-architecture/references/self-modification.md +269 -0
  104. package/plugins/compound-engineering/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
  105. package/plugins/compound-engineering/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
  106. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/SKILL.md +184 -0
  107. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
  108. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
  109. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
  110. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/resources.md +119 -0
  111. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
  112. package/plugins/compound-engineering/skills/compound-docs/SKILL.md +510 -0
  113. package/plugins/compound-engineering/skills/compound-docs/assets/critical-pattern-template.md +34 -0
  114. package/plugins/compound-engineering/skills/compound-docs/assets/resolution-template.md +93 -0
  115. package/plugins/compound-engineering/skills/compound-docs/references/yaml-schema.md +65 -0
  116. package/plugins/compound-engineering/skills/compound-docs/schema.yaml +176 -0
  117. package/plugins/compound-engineering/skills/create-agent-skills/SKILL.md +299 -0
  118. package/plugins/compound-engineering/skills/create-agent-skills/references/api-security.md +226 -0
  119. package/plugins/compound-engineering/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
  120. package/plugins/compound-engineering/skills/create-agent-skills/references/best-practices.md +404 -0
  121. package/plugins/compound-engineering/skills/create-agent-skills/references/common-patterns.md +595 -0
  122. package/plugins/compound-engineering/skills/create-agent-skills/references/core-principles.md +437 -0
  123. package/plugins/compound-engineering/skills/create-agent-skills/references/executable-code.md +175 -0
  124. package/plugins/compound-engineering/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
  125. package/plugins/compound-engineering/skills/create-agent-skills/references/official-spec.md +185 -0
  126. package/plugins/compound-engineering/skills/create-agent-skills/references/recommended-structure.md +168 -0
  127. package/plugins/compound-engineering/skills/create-agent-skills/references/skill-structure.md +372 -0
  128. package/plugins/compound-engineering/skills/create-agent-skills/references/using-scripts.md +113 -0
  129. package/plugins/compound-engineering/skills/create-agent-skills/references/using-templates.md +112 -0
  130. package/plugins/compound-engineering/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
  131. package/plugins/compound-engineering/skills/create-agent-skills/templates/router-skill.md +73 -0
  132. package/plugins/compound-engineering/skills/create-agent-skills/templates/simple-skill.md +33 -0
  133. package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-reference.md +96 -0
  134. package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-script.md +93 -0
  135. package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-template.md +74 -0
  136. package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-workflow.md +120 -0
  137. package/plugins/compound-engineering/skills/create-agent-skills/workflows/audit-skill.md +138 -0
  138. package/plugins/compound-engineering/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
  139. package/plugins/compound-engineering/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
  140. package/plugins/compound-engineering/skills/create-agent-skills/workflows/get-guidance.md +121 -0
  141. package/plugins/compound-engineering/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
  142. package/plugins/compound-engineering/skills/create-agent-skills/workflows/verify-skill.md +204 -0
  143. package/plugins/compound-engineering/skills/dhh-rails-style/SKILL.md +185 -0
  144. package/plugins/compound-engineering/skills/dhh-rails-style/references/architecture.md +653 -0
  145. package/plugins/compound-engineering/skills/dhh-rails-style/references/controllers.md +303 -0
  146. package/plugins/compound-engineering/skills/dhh-rails-style/references/frontend.md +510 -0
  147. package/plugins/compound-engineering/skills/dhh-rails-style/references/gems.md +266 -0
  148. package/plugins/compound-engineering/skills/dhh-rails-style/references/models.md +359 -0
  149. package/plugins/compound-engineering/skills/dhh-rails-style/references/testing.md +338 -0
  150. package/plugins/compound-engineering/skills/dspy-ruby/SKILL.md +594 -0
  151. package/plugins/compound-engineering/skills/dspy-ruby/assets/config-template.rb +359 -0
  152. package/plugins/compound-engineering/skills/dspy-ruby/assets/module-template.rb +326 -0
  153. package/plugins/compound-engineering/skills/dspy-ruby/assets/signature-template.rb +143 -0
  154. package/plugins/compound-engineering/skills/dspy-ruby/references/core-concepts.md +265 -0
  155. package/plugins/compound-engineering/skills/dspy-ruby/references/optimization.md +623 -0
  156. package/plugins/compound-engineering/skills/dspy-ruby/references/providers.md +338 -0
  157. package/plugins/compound-engineering/skills/every-style-editor/SKILL.md +134 -0
  158. package/plugins/compound-engineering/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
  159. package/plugins/compound-engineering/skills/file-todos/SKILL.md +251 -0
  160. package/plugins/compound-engineering/skills/file-todos/assets/todo-template.md +155 -0
  161. package/plugins/compound-engineering/skills/frontend-design/SKILL.md +42 -0
  162. package/plugins/compound-engineering/skills/gemini-imagegen/SKILL.md +237 -0
  163. package/plugins/compound-engineering/skills/gemini-imagegen/requirements.txt +2 -0
  164. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/compose_images.py +157 -0
  165. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/edit_image.py +144 -0
  166. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/gemini_images.py +263 -0
  167. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/generate_image.py +133 -0
  168. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/multi_turn_chat.py +216 -0
  169. package/plugins/compound-engineering/skills/git-worktree/SKILL.md +302 -0
  170. package/plugins/compound-engineering/skills/git-worktree/scripts/worktree-manager.sh +345 -0
  171. package/plugins/compound-engineering/skills/rclone/SKILL.md +150 -0
  172. package/plugins/compound-engineering/skills/rclone/scripts/check_setup.sh +60 -0
  173. package/plugins/compound-engineering/skills/skill-creator/SKILL.md +209 -0
  174. package/plugins/compound-engineering/skills/skill-creator/scripts/init_skill.py +303 -0
  175. package/plugins/compound-engineering/skills/skill-creator/scripts/package_skill.py +110 -0
  176. package/plugins/compound-engineering/skills/skill-creator/scripts/quick_validate.py +65 -0
  177. package/src/commands/convert.ts +156 -0
  178. package/src/commands/install.ts +221 -0
  179. package/src/commands/list.ts +37 -0
  180. package/src/converters/claude-to-codex.ts +124 -0
  181. package/src/converters/claude-to-opencode.ts +392 -0
  182. package/src/index.ts +20 -0
  183. package/src/parsers/claude.ts +248 -0
  184. package/src/targets/codex.ts +91 -0
  185. package/src/targets/index.ts +29 -0
  186. package/src/targets/opencode.ts +48 -0
  187. package/src/types/claude.ts +88 -0
  188. package/src/types/codex.ts +23 -0
  189. package/src/types/opencode.ts +54 -0
  190. package/src/utils/codex-agents.ts +64 -0
  191. package/src/utils/files.ts +64 -0
  192. package/src/utils/frontmatter.ts +65 -0
  193. package/tests/claude-parser.test.ts +89 -0
  194. package/tests/cli.test.ts +289 -0
  195. package/tests/codex-agents.test.ts +62 -0
  196. package/tests/codex-converter.test.ts +121 -0
  197. package/tests/codex-writer.test.ts +76 -0
  198. package/tests/converter.test.ts +171 -0
  199. package/tests/fixtures/custom-paths/.claude-plugin/plugin.json +8 -0
  200. package/tests/fixtures/custom-paths/agents/default-agent.md +5 -0
  201. package/tests/fixtures/custom-paths/commands/default-command.md +5 -0
  202. package/tests/fixtures/custom-paths/custom-agents/custom-agent.md +5 -0
  203. package/tests/fixtures/custom-paths/custom-commands/custom-command.md +5 -0
  204. package/tests/fixtures/custom-paths/custom-hooks/hooks.json +7 -0
  205. package/tests/fixtures/custom-paths/custom-skills/custom-skill/SKILL.md +5 -0
  206. package/tests/fixtures/custom-paths/hooks/hooks.json +7 -0
  207. package/tests/fixtures/custom-paths/skills/default-skill/SKILL.md +5 -0
  208. package/tests/fixtures/invalid-command-path/.claude-plugin/plugin.json +5 -0
  209. package/tests/fixtures/invalid-hooks-path/.claude-plugin/plugin.json +5 -0
  210. package/tests/fixtures/invalid-mcp-path/.claude-plugin/plugin.json +5 -0
  211. package/tests/fixtures/mcp-file/.claude-plugin/plugin.json +5 -0
  212. package/tests/fixtures/mcp-file/.mcp.json +6 -0
  213. package/tests/fixtures/sample-plugin/.claude-plugin/plugin.json +30 -0
  214. package/tests/fixtures/sample-plugin/agents/agent-one.md +10 -0
  215. package/tests/fixtures/sample-plugin/agents/security-reviewer.md +7 -0
  216. package/tests/fixtures/sample-plugin/commands/command-one.md +7 -0
  217. package/tests/fixtures/sample-plugin/commands/model-command.md +8 -0
  218. package/tests/fixtures/sample-plugin/commands/nested/command-two.md +9 -0
  219. package/tests/fixtures/sample-plugin/commands/pattern-command.md +7 -0
  220. package/tests/fixtures/sample-plugin/commands/skill-command.md +7 -0
  221. package/tests/fixtures/sample-plugin/commands/todo-command.md +7 -0
  222. package/tests/fixtures/sample-plugin/hooks/hooks.json +156 -0
  223. package/tests/fixtures/sample-plugin/skills/skill-one/SKILL.md +6 -0
  224. package/tests/frontmatter.test.ts +20 -0
  225. package/tests/opencode-writer.test.ts +62 -0
  226. package/tsconfig.json +14 -0
@@ -0,0 +1,171 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import path from "path"
3
+ import { loadClaudePlugin } from "../src/parsers/claude"
4
+ import { convertClaudeToOpenCode } from "../src/converters/claude-to-opencode"
5
+ import { parseFrontmatter } from "../src/utils/frontmatter"
6
+
7
+ const fixtureRoot = path.join(import.meta.dir, "fixtures", "sample-plugin")
8
+
9
+ describe("convertClaudeToOpenCode", () => {
10
+ test("maps commands, permissions, and agents", async () => {
11
+ const plugin = await loadClaudePlugin(fixtureRoot)
12
+ const bundle = convertClaudeToOpenCode(plugin, {
13
+ agentMode: "subagent",
14
+ inferTemperature: false,
15
+ permissions: "from-commands",
16
+ })
17
+
18
+ expect(bundle.config.command?.["workflows:review"]).toBeDefined()
19
+ expect(bundle.config.command?.["plan_review"]).toBeDefined()
20
+
21
+ const permission = bundle.config.permission as Record<string, string | Record<string, string>>
22
+ expect(Object.keys(permission).sort()).toEqual([
23
+ "bash",
24
+ "edit",
25
+ "glob",
26
+ "grep",
27
+ "list",
28
+ "patch",
29
+ "question",
30
+ "read",
31
+ "skill",
32
+ "task",
33
+ "todoread",
34
+ "todowrite",
35
+ "webfetch",
36
+ "write",
37
+ ])
38
+ expect(permission.edit).toBe("allow")
39
+ expect(permission.write).toBe("allow")
40
+ const bashPermission = permission.bash as Record<string, string>
41
+ expect(bashPermission["ls *"]).toBe("allow")
42
+ expect(bashPermission["git *"]).toBe("allow")
43
+ expect(permission.webfetch).toBe("allow")
44
+
45
+ const readPermission = permission.read as Record<string, string>
46
+ expect(readPermission["*"]).toBe("deny")
47
+ expect(readPermission[".env"]).toBe("allow")
48
+
49
+ expect(permission.question).toBe("allow")
50
+ expect(permission.todowrite).toBe("allow")
51
+ expect(permission.todoread).toBe("allow")
52
+
53
+ const agentFile = bundle.agents.find((agent) => agent.name === "repo-research-analyst")
54
+ expect(agentFile).toBeDefined()
55
+ const parsed = parseFrontmatter(agentFile!.content)
56
+ expect(parsed.data.mode).toBe("subagent")
57
+ })
58
+
59
+ test("normalizes models and infers temperature", async () => {
60
+ const plugin = await loadClaudePlugin(fixtureRoot)
61
+ const bundle = convertClaudeToOpenCode(plugin, {
62
+ agentMode: "subagent",
63
+ inferTemperature: true,
64
+ permissions: "none",
65
+ })
66
+
67
+ const securityAgent = bundle.agents.find((agent) => agent.name === "security-sentinel")
68
+ expect(securityAgent).toBeDefined()
69
+ const parsed = parseFrontmatter(securityAgent!.content)
70
+ expect(parsed.data.model).toBe("anthropic/claude-sonnet-4-20250514")
71
+ expect(parsed.data.temperature).toBe(0.1)
72
+
73
+ const modelCommand = bundle.config.command?.["workflows:work"]
74
+ expect(modelCommand?.model).toBe("openai/gpt-4o")
75
+ })
76
+
77
+ test("converts hooks into plugin file", async () => {
78
+ const plugin = await loadClaudePlugin(fixtureRoot)
79
+ const bundle = convertClaudeToOpenCode(plugin, {
80
+ agentMode: "subagent",
81
+ inferTemperature: false,
82
+ permissions: "none",
83
+ })
84
+
85
+ const hookFile = bundle.plugins.find((file) => file.name === "converted-hooks.ts")
86
+ expect(hookFile).toBeDefined()
87
+ expect(hookFile!.content).toContain("\"tool.execute.before\"")
88
+ expect(hookFile!.content).toContain("\"tool.execute.after\"")
89
+ expect(hookFile!.content).toContain("\"session.created\"")
90
+ expect(hookFile!.content).toContain("\"session.deleted\"")
91
+ expect(hookFile!.content).toContain("\"session.idle\"")
92
+ expect(hookFile!.content).toContain("\"experimental.session.compacting\"")
93
+ expect(hookFile!.content).toContain("\"permission.requested\"")
94
+ expect(hookFile!.content).toContain("\"permission.replied\"")
95
+ expect(hookFile!.content).toContain("\"message.created\"")
96
+ expect(hookFile!.content).toContain("\"message.updated\"")
97
+ expect(hookFile!.content).toContain("echo before")
98
+ expect(hookFile!.content).toContain("echo before two")
99
+ expect(hookFile!.content).toContain("// timeout: 30s")
100
+ expect(hookFile!.content).toContain("// Prompt hook for Write|Edit")
101
+ expect(hookFile!.content).toContain("// Agent hook for Write|Edit: security-sentinel")
102
+ })
103
+
104
+ test("converts MCP servers", async () => {
105
+ const plugin = await loadClaudePlugin(fixtureRoot)
106
+ const bundle = convertClaudeToOpenCode(plugin, {
107
+ agentMode: "subagent",
108
+ inferTemperature: false,
109
+ permissions: "none",
110
+ })
111
+
112
+ const mcp = bundle.config.mcp ?? {}
113
+ expect(mcp["local-tooling"]).toEqual({
114
+ type: "local",
115
+ command: ["echo", "fixture"],
116
+ environment: undefined,
117
+ enabled: true,
118
+ })
119
+ expect(mcp.context7).toEqual({
120
+ type: "remote",
121
+ url: "https://mcp.context7.com/mcp",
122
+ headers: undefined,
123
+ enabled: true,
124
+ })
125
+ })
126
+
127
+ test("permission modes set expected keys", async () => {
128
+ const plugin = await loadClaudePlugin(fixtureRoot)
129
+ const noneBundle = convertClaudeToOpenCode(plugin, {
130
+ agentMode: "subagent",
131
+ inferTemperature: false,
132
+ permissions: "none",
133
+ })
134
+ expect(noneBundle.config.permission).toBeUndefined()
135
+
136
+ const broadBundle = convertClaudeToOpenCode(plugin, {
137
+ agentMode: "subagent",
138
+ inferTemperature: false,
139
+ permissions: "broad",
140
+ })
141
+ expect(broadBundle.config.permission).toEqual({
142
+ read: "allow",
143
+ write: "allow",
144
+ edit: "allow",
145
+ bash: "allow",
146
+ grep: "allow",
147
+ glob: "allow",
148
+ list: "allow",
149
+ webfetch: "allow",
150
+ skill: "allow",
151
+ patch: "allow",
152
+ task: "allow",
153
+ question: "allow",
154
+ todowrite: "allow",
155
+ todoread: "allow",
156
+ })
157
+ })
158
+
159
+ test("supports primary agent mode", async () => {
160
+ const plugin = await loadClaudePlugin(fixtureRoot)
161
+ const bundle = convertClaudeToOpenCode(plugin, {
162
+ agentMode: "primary",
163
+ inferTemperature: false,
164
+ permissions: "none",
165
+ })
166
+
167
+ const agentFile = bundle.agents.find((agent) => agent.name === "repo-research-analyst")
168
+ const parsed = parseFrontmatter(agentFile!.content)
169
+ expect(parsed.data.mode).toBe("primary")
170
+ })
171
+ })
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "custom-paths",
3
+ "version": "1.0.0",
4
+ "agents": "./custom-agents",
5
+ "commands": ["./custom-commands"],
6
+ "skills": "./custom-skills",
7
+ "hooks": "./custom-hooks/hooks.json"
8
+ }
@@ -0,0 +1,5 @@
1
+ ---
2
+ name: default-agent
3
+ ---
4
+
5
+ Default agent
@@ -0,0 +1,5 @@
1
+ ---
2
+ name: default-command
3
+ ---
4
+
5
+ Default command
@@ -0,0 +1,5 @@
1
+ ---
2
+ name: custom-agent
3
+ ---
4
+
5
+ Custom agent
@@ -0,0 +1,5 @@
1
+ ---
2
+ name: custom-command
3
+ ---
4
+
5
+ Custom command
@@ -0,0 +1,7 @@
1
+ {
2
+ "hooks": {
3
+ "PostToolUse": [
4
+ { "matcher": "Write", "hooks": [{ "type": "command", "command": "echo custom" }] }
5
+ ]
6
+ }
7
+ }
@@ -0,0 +1,5 @@
1
+ ---
2
+ name: custom-skill
3
+ ---
4
+
5
+ Custom skill
@@ -0,0 +1,7 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ { "matcher": "Read", "hooks": [{ "type": "command", "command": "echo default" }] }
5
+ ]
6
+ }
7
+ }
@@ -0,0 +1,5 @@
1
+ ---
2
+ name: default-skill
3
+ ---
4
+
5
+ Default skill
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "invalid-command-path",
3
+ "version": "1.0.0",
4
+ "commands": ["../outside-commands"]
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "invalid-hooks-path",
3
+ "version": "1.0.0",
4
+ "hooks": ["../outside-hooks.json"]
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "invalid-mcp-path",
3
+ "version": "1.0.0",
4
+ "mcpServers": ["../outside-mcp.json"]
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "mcp-file",
3
+ "version": "1.0.0",
4
+ "description": "MCP file fixture"
5
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "remote": {
3
+ "type": "sse",
4
+ "url": "https://example.com/stream"
5
+ }
6
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "compound-engineering",
3
+ "version": "2.27.0",
4
+ "description": "Fixture aligned with the Compound Engineering plugin",
5
+ "author": {
6
+ "name": "Kieran Klaassen",
7
+ "email": "kieran@every.to",
8
+ "url": "https://github.com/kieranklaassen"
9
+ },
10
+ "homepage": "https://every.to/source-code/my-ai-had-already-fixed-the-code-before-i-saw-it",
11
+ "repository": "https://github.com/EveryInc/compound-engineering-plugin",
12
+ "license": "MIT",
13
+ "keywords": [
14
+ "compound-engineering",
15
+ "workflow-automation",
16
+ "code-review",
17
+ "agents"
18
+ ],
19
+ "mcpServers": {
20
+ "context7": {
21
+ "type": "http",
22
+ "url": "https://mcp.context7.com/mcp"
23
+ },
24
+ "local-tooling": {
25
+ "type": "stdio",
26
+ "command": "echo",
27
+ "args": ["fixture"]
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: repo-research-analyst
3
+ description: Research repository structure and conventions
4
+ capabilities:
5
+ - "Capability A"
6
+ - "Capability B"
7
+ model: inherit
8
+ ---
9
+
10
+ Repo research analyst body.
@@ -0,0 +1,7 @@
1
+ ---
2
+ name: security-sentinel
3
+ description: Security audits and vulnerability assessments
4
+ model: claude-sonnet-4-20250514
5
+ ---
6
+
7
+ Security sentinel body.
@@ -0,0 +1,7 @@
1
+ ---
2
+ name: workflows:review
3
+ description: Run a multi-agent review workflow
4
+ allowed-tools: Read, Write, Edit, Bash(ls:*), Bash(git:*), Grep, Glob, List, Patch, Task
5
+ ---
6
+
7
+ Workflows review body.
@@ -0,0 +1,8 @@
1
+ ---
2
+ name: workflows:work
3
+ description: Execute planned tasks step by step
4
+ model: gpt-4o
5
+ allowed-tools: WebFetch
6
+ ---
7
+
8
+ Workflows work body.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: plan_review
3
+ description: Review a plan with multiple agents
4
+ allowed-tools:
5
+ - Read
6
+ - Edit
7
+ ---
8
+
9
+ Plan review body.
@@ -0,0 +1,7 @@
1
+ ---
2
+ name: report-bug
3
+ description: Report a bug with structured context
4
+ allowed-tools: Read(.env), Bash(git:*)
5
+ ---
6
+
7
+ Report bug body.
@@ -0,0 +1,7 @@
1
+ ---
2
+ name: create-agent-skill
3
+ description: Create or edit a Claude Code skill
4
+ allowed-tools: Skill(create-agent-skills)
5
+ ---
6
+
7
+ Create agent skill body.
@@ -0,0 +1,7 @@
1
+ ---
2
+ name: workflows:plan
3
+ description: Create a structured plan from requirements
4
+ allowed-tools: Question, TodoWrite, TodoRead
5
+ ---
6
+
7
+ Workflows plan body.
@@ -0,0 +1,156 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "Bash",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "echo before",
10
+ "timeout": 30
11
+ },
12
+ {
13
+ "type": "command",
14
+ "command": "echo before two"
15
+ }
16
+ ]
17
+ }
18
+ ],
19
+ "PostToolUse": [
20
+ {
21
+ "matcher": "Write|Edit",
22
+ "hooks": [
23
+ {
24
+ "type": "prompt",
25
+ "prompt": "After write"
26
+ },
27
+ {
28
+ "type": "agent",
29
+ "agent": "security-sentinel"
30
+ }
31
+ ]
32
+ }
33
+ ],
34
+ "PostToolUseFailure": [
35
+ {
36
+ "matcher": "Bash",
37
+ "hooks": [
38
+ {
39
+ "type": "command",
40
+ "command": "echo failed"
41
+ }
42
+ ]
43
+ }
44
+ ],
45
+ "PermissionRequest": [
46
+ {
47
+ "matcher": "Bash",
48
+ "hooks": [
49
+ {
50
+ "type": "command",
51
+ "command": "echo permission"
52
+ }
53
+ ]
54
+ }
55
+ ],
56
+ "UserPromptSubmit": [
57
+ {
58
+ "matcher": "*",
59
+ "hooks": [
60
+ {
61
+ "type": "command",
62
+ "command": "echo prompt"
63
+ }
64
+ ]
65
+ }
66
+ ],
67
+ "Notification": [
68
+ {
69
+ "matcher": "*",
70
+ "hooks": [
71
+ {
72
+ "type": "command",
73
+ "command": "echo notify"
74
+ }
75
+ ]
76
+ }
77
+ ],
78
+ "SessionStart": [
79
+ {
80
+ "matcher": "*",
81
+ "hooks": [
82
+ {
83
+ "type": "command",
84
+ "command": "echo session start"
85
+ }
86
+ ]
87
+ }
88
+ ],
89
+ "SessionEnd": [
90
+ {
91
+ "matcher": "*",
92
+ "hooks": [
93
+ {
94
+ "type": "command",
95
+ "command": "echo session end"
96
+ }
97
+ ]
98
+ }
99
+ ],
100
+ "Stop": [
101
+ {
102
+ "matcher": "*",
103
+ "hooks": [
104
+ {
105
+ "type": "command",
106
+ "command": "echo stop"
107
+ }
108
+ ]
109
+ }
110
+ ],
111
+ "PreCompact": [
112
+ {
113
+ "matcher": "*",
114
+ "hooks": [
115
+ {
116
+ "type": "command",
117
+ "command": "echo compact"
118
+ }
119
+ ]
120
+ }
121
+ ],
122
+ "Setup": [
123
+ {
124
+ "matcher": "*",
125
+ "hooks": [
126
+ {
127
+ "type": "command",
128
+ "command": "echo setup"
129
+ }
130
+ ]
131
+ }
132
+ ],
133
+ "SubagentStart": [
134
+ {
135
+ "matcher": "*",
136
+ "hooks": [
137
+ {
138
+ "type": "command",
139
+ "command": "echo subagent start"
140
+ }
141
+ ]
142
+ }
143
+ ],
144
+ "SubagentStop": [
145
+ {
146
+ "matcher": "*",
147
+ "hooks": [
148
+ {
149
+ "type": "command",
150
+ "command": "echo subagent stop"
151
+ }
152
+ ]
153
+ }
154
+ ]
155
+ }
156
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ name: skill-one
3
+ description: Sample skill
4
+ ---
5
+
6
+ Skill body.
@@ -0,0 +1,20 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { formatFrontmatter, parseFrontmatter } from "../src/utils/frontmatter"
3
+
4
+ describe("frontmatter", () => {
5
+ test("parseFrontmatter returns body when no frontmatter", () => {
6
+ const raw = "Hello\nWorld"
7
+ const result = parseFrontmatter(raw)
8
+ expect(result.data).toEqual({})
9
+ expect(result.body).toBe(raw)
10
+ })
11
+
12
+ test("formatFrontmatter round trips", () => {
13
+ const body = "Body text"
14
+ const formatted = formatFrontmatter({ name: "agent", description: "Test" }, body)
15
+ const parsed = parseFrontmatter(formatted)
16
+ expect(parsed.data.name).toBe("agent")
17
+ expect(parsed.data.description).toBe("Test")
18
+ expect(parsed.body.trim()).toBe(body)
19
+ })
20
+ })
@@ -0,0 +1,62 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { promises as fs } from "fs"
3
+ import path from "path"
4
+ import os from "os"
5
+ import { writeOpenCodeBundle } from "../src/targets/opencode"
6
+ import type { OpenCodeBundle } from "../src/types/opencode"
7
+
8
+ async function exists(filePath: string): Promise<boolean> {
9
+ try {
10
+ await fs.access(filePath)
11
+ return true
12
+ } catch {
13
+ return false
14
+ }
15
+ }
16
+
17
+ describe("writeOpenCodeBundle", () => {
18
+ test("writes config, agents, plugins, and skills", async () => {
19
+ const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-test-"))
20
+ const bundle: OpenCodeBundle = {
21
+ config: { $schema: "https://opencode.ai/config.json" },
22
+ agents: [{ name: "agent-one", content: "Agent content" }],
23
+ plugins: [{ name: "hook.ts", content: "export {}" }],
24
+ skillDirs: [
25
+ {
26
+ name: "skill-one",
27
+ sourceDir: path.join(import.meta.dir, "fixtures", "sample-plugin", "skills", "skill-one"),
28
+ },
29
+ ],
30
+ }
31
+
32
+ await writeOpenCodeBundle(tempRoot, bundle)
33
+
34
+ expect(await exists(path.join(tempRoot, "opencode.json"))).toBe(true)
35
+ expect(await exists(path.join(tempRoot, ".opencode", "agents", "agent-one.md"))).toBe(true)
36
+ expect(await exists(path.join(tempRoot, ".opencode", "plugins", "hook.ts"))).toBe(true)
37
+ expect(await exists(path.join(tempRoot, ".opencode", "skills", "skill-one", "SKILL.md"))).toBe(true)
38
+ })
39
+
40
+ test("writes directly into a .opencode output root", async () => {
41
+ const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-root-"))
42
+ const outputRoot = path.join(tempRoot, ".opencode")
43
+ const bundle: OpenCodeBundle = {
44
+ config: { $schema: "https://opencode.ai/config.json" },
45
+ agents: [{ name: "agent-one", content: "Agent content" }],
46
+ plugins: [],
47
+ skillDirs: [
48
+ {
49
+ name: "skill-one",
50
+ sourceDir: path.join(import.meta.dir, "fixtures", "sample-plugin", "skills", "skill-one"),
51
+ },
52
+ ],
53
+ }
54
+
55
+ await writeOpenCodeBundle(outputRoot, bundle)
56
+
57
+ expect(await exists(path.join(outputRoot, "opencode.json"))).toBe(true)
58
+ expect(await exists(path.join(outputRoot, "agents", "agent-one.md"))).toBe(true)
59
+ expect(await exists(path.join(outputRoot, "skills", "skill-one", "SKILL.md"))).toBe(true)
60
+ expect(await exists(path.join(outputRoot, ".opencode"))).toBe(false)
61
+ })
62
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "strict": true,
7
+ "resolveJsonModule": true,
8
+ "esModuleInterop": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "skipLibCheck": true,
11
+ "types": ["bun-types"]
12
+ },
13
+ "include": ["src/**/*.ts"]
14
+ }