compound-engineering-pi 0.2.3

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 (332) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/bin/compound-engineering-pi +12 -0
  4. package/bin/compound-plugin +12 -0
  5. package/compound-engineering-pi +12 -0
  6. package/compound-plugin +5 -0
  7. package/docs/pi.md +152 -0
  8. package/extensions/compound-engineering-compat.ts +452 -0
  9. package/package.json +84 -0
  10. package/pi-resources/compound-engineering/mcporter.json +7 -0
  11. package/plugins/coding-tutor/.claude-plugin/plugin.json +9 -0
  12. package/plugins/coding-tutor/README.md +37 -0
  13. package/plugins/coding-tutor/commands/quiz-me.md +1 -0
  14. package/plugins/coding-tutor/commands/sync-tutorials.md +25 -0
  15. package/plugins/coding-tutor/commands/teach-me.md +1 -0
  16. package/plugins/coding-tutor/skills/coding-tutor/SKILL.md +214 -0
  17. package/plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py +207 -0
  18. package/plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py +193 -0
  19. package/plugins/coding-tutor/skills/coding-tutor/scripts/quiz_priority.py +190 -0
  20. package/plugins/coding-tutor/skills/coding-tutor/scripts/setup_tutorials.py +118 -0
  21. package/plugins/compound-engineering/.claude-plugin/plugin.json +33 -0
  22. package/plugins/compound-engineering/CHANGELOG.md +457 -0
  23. package/plugins/compound-engineering/CLAUDE.md +89 -0
  24. package/plugins/compound-engineering/LICENSE +21 -0
  25. package/plugins/compound-engineering/README.md +232 -0
  26. package/plugins/compound-engineering/agents/design/design-implementation-reviewer.md +109 -0
  27. package/plugins/compound-engineering/agents/design/design-iterator.md +224 -0
  28. package/plugins/compound-engineering/agents/design/figma-design-sync.md +190 -0
  29. package/plugins/compound-engineering/agents/docs/ankane-readme-writer.md +65 -0
  30. package/plugins/compound-engineering/agents/research/best-practices-researcher.md +126 -0
  31. package/plugins/compound-engineering/agents/research/framework-docs-researcher.md +106 -0
  32. package/plugins/compound-engineering/agents/research/git-history-analyzer.md +59 -0
  33. package/plugins/compound-engineering/agents/research/learnings-researcher.md +264 -0
  34. package/plugins/compound-engineering/agents/research/repo-research-analyst.md +135 -0
  35. package/plugins/compound-engineering/agents/review/agent-native-reviewer.md +261 -0
  36. package/plugins/compound-engineering/agents/review/architecture-strategist.md +67 -0
  37. package/plugins/compound-engineering/agents/review/code-simplicity-reviewer.md +101 -0
  38. package/plugins/compound-engineering/agents/review/data-integrity-guardian.md +85 -0
  39. package/plugins/compound-engineering/agents/review/data-migration-expert.md +112 -0
  40. package/plugins/compound-engineering/agents/review/deployment-verification-agent.md +174 -0
  41. package/plugins/compound-engineering/agents/review/dhh-rails-reviewer.md +66 -0
  42. package/plugins/compound-engineering/agents/review/julik-frontend-races-reviewer.md +221 -0
  43. package/plugins/compound-engineering/agents/review/kieran-python-reviewer.md +133 -0
  44. package/plugins/compound-engineering/agents/review/kieran-rails-reviewer.md +115 -0
  45. package/plugins/compound-engineering/agents/review/kieran-typescript-reviewer.md +124 -0
  46. package/plugins/compound-engineering/agents/review/pattern-recognition-specialist.md +72 -0
  47. package/plugins/compound-engineering/agents/review/performance-oracle.md +137 -0
  48. package/plugins/compound-engineering/agents/review/schema-drift-detector.md +154 -0
  49. package/plugins/compound-engineering/agents/review/security-sentinel.md +114 -0
  50. package/plugins/compound-engineering/agents/workflow/bug-reproduction-validator.md +82 -0
  51. package/plugins/compound-engineering/agents/workflow/every-style-editor.md +64 -0
  52. package/plugins/compound-engineering/agents/workflow/lint.md +16 -0
  53. package/plugins/compound-engineering/agents/workflow/pr-comment-resolver.md +84 -0
  54. package/plugins/compound-engineering/agents/workflow/spec-flow-analyzer.md +134 -0
  55. package/plugins/compound-engineering/commands/agent-native-audit.md +278 -0
  56. package/plugins/compound-engineering/commands/changelog.md +138 -0
  57. package/plugins/compound-engineering/commands/create-agent-skill.md +9 -0
  58. package/plugins/compound-engineering/commands/deepen-plan.md +546 -0
  59. package/plugins/compound-engineering/commands/deploy-docs.md +113 -0
  60. package/plugins/compound-engineering/commands/feature-video.md +342 -0
  61. package/plugins/compound-engineering/commands/generate_command.md +163 -0
  62. package/plugins/compound-engineering/commands/heal-skill.md +143 -0
  63. package/plugins/compound-engineering/commands/lfg.md +20 -0
  64. package/plugins/compound-engineering/commands/release-docs.md +212 -0
  65. package/plugins/compound-engineering/commands/report-bug.md +151 -0
  66. package/plugins/compound-engineering/commands/reproduce-bug.md +100 -0
  67. package/plugins/compound-engineering/commands/resolve_parallel.md +35 -0
  68. package/plugins/compound-engineering/commands/resolve_todo_parallel.md +37 -0
  69. package/plugins/compound-engineering/commands/slfg.md +32 -0
  70. package/plugins/compound-engineering/commands/technical_review.md +8 -0
  71. package/plugins/compound-engineering/commands/test-browser.md +339 -0
  72. package/plugins/compound-engineering/commands/test-xcode.md +332 -0
  73. package/plugins/compound-engineering/commands/triage.md +311 -0
  74. package/plugins/compound-engineering/commands/workflows/brainstorm.md +124 -0
  75. package/plugins/compound-engineering/commands/workflows/compound.md +239 -0
  76. package/plugins/compound-engineering/commands/workflows/plan.md +551 -0
  77. package/plugins/compound-engineering/commands/workflows/review.md +526 -0
  78. package/plugins/compound-engineering/commands/workflows/work.md +433 -0
  79. package/plugins/compound-engineering/skills/agent-browser/SKILL.md +223 -0
  80. package/plugins/compound-engineering/skills/agent-native-architecture/SKILL.md +435 -0
  81. package/plugins/compound-engineering/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
  82. package/plugins/compound-engineering/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
  83. package/plugins/compound-engineering/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
  84. package/plugins/compound-engineering/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
  85. package/plugins/compound-engineering/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
  86. package/plugins/compound-engineering/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
  87. package/plugins/compound-engineering/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
  88. package/plugins/compound-engineering/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
  89. package/plugins/compound-engineering/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
  90. package/plugins/compound-engineering/skills/agent-native-architecture/references/product-implications.md +443 -0
  91. package/plugins/compound-engineering/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
  92. package/plugins/compound-engineering/skills/agent-native-architecture/references/self-modification.md +269 -0
  93. package/plugins/compound-engineering/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
  94. package/plugins/compound-engineering/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
  95. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/SKILL.md +184 -0
  96. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
  97. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
  98. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
  99. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/resources.md +119 -0
  100. package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
  101. package/plugins/compound-engineering/skills/brainstorming/SKILL.md +190 -0
  102. package/plugins/compound-engineering/skills/compound-docs/SKILL.md +511 -0
  103. package/plugins/compound-engineering/skills/compound-docs/assets/critical-pattern-template.md +34 -0
  104. package/plugins/compound-engineering/skills/compound-docs/assets/resolution-template.md +93 -0
  105. package/plugins/compound-engineering/skills/compound-docs/references/yaml-schema.md +65 -0
  106. package/plugins/compound-engineering/skills/compound-docs/schema.yaml +176 -0
  107. package/plugins/compound-engineering/skills/create-agent-skills/SKILL.md +275 -0
  108. package/plugins/compound-engineering/skills/create-agent-skills/references/api-security.md +226 -0
  109. package/plugins/compound-engineering/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
  110. package/plugins/compound-engineering/skills/create-agent-skills/references/best-practices.md +404 -0
  111. package/plugins/compound-engineering/skills/create-agent-skills/references/common-patterns.md +595 -0
  112. package/plugins/compound-engineering/skills/create-agent-skills/references/core-principles.md +437 -0
  113. package/plugins/compound-engineering/skills/create-agent-skills/references/executable-code.md +175 -0
  114. package/plugins/compound-engineering/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
  115. package/plugins/compound-engineering/skills/create-agent-skills/references/official-spec.md +134 -0
  116. package/plugins/compound-engineering/skills/create-agent-skills/references/recommended-structure.md +168 -0
  117. package/plugins/compound-engineering/skills/create-agent-skills/references/skill-structure.md +152 -0
  118. package/plugins/compound-engineering/skills/create-agent-skills/references/using-scripts.md +113 -0
  119. package/plugins/compound-engineering/skills/create-agent-skills/references/using-templates.md +112 -0
  120. package/plugins/compound-engineering/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
  121. package/plugins/compound-engineering/skills/create-agent-skills/templates/router-skill.md +73 -0
  122. package/plugins/compound-engineering/skills/create-agent-skills/templates/simple-skill.md +33 -0
  123. package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-reference.md +96 -0
  124. package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-script.md +93 -0
  125. package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-template.md +74 -0
  126. package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-workflow.md +120 -0
  127. package/plugins/compound-engineering/skills/create-agent-skills/workflows/audit-skill.md +138 -0
  128. package/plugins/compound-engineering/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
  129. package/plugins/compound-engineering/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
  130. package/plugins/compound-engineering/skills/create-agent-skills/workflows/get-guidance.md +121 -0
  131. package/plugins/compound-engineering/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
  132. package/plugins/compound-engineering/skills/create-agent-skills/workflows/verify-skill.md +204 -0
  133. package/plugins/compound-engineering/skills/dhh-rails-style/SKILL.md +185 -0
  134. package/plugins/compound-engineering/skills/dhh-rails-style/references/architecture.md +653 -0
  135. package/plugins/compound-engineering/skills/dhh-rails-style/references/controllers.md +303 -0
  136. package/plugins/compound-engineering/skills/dhh-rails-style/references/frontend.md +510 -0
  137. package/plugins/compound-engineering/skills/dhh-rails-style/references/gems.md +266 -0
  138. package/plugins/compound-engineering/skills/dhh-rails-style/references/models.md +359 -0
  139. package/plugins/compound-engineering/skills/dhh-rails-style/references/testing.md +338 -0
  140. package/plugins/compound-engineering/skills/document-review/SKILL.md +87 -0
  141. package/plugins/compound-engineering/skills/dspy-ruby/SKILL.md +737 -0
  142. package/plugins/compound-engineering/skills/dspy-ruby/assets/config-template.rb +187 -0
  143. package/plugins/compound-engineering/skills/dspy-ruby/assets/module-template.rb +300 -0
  144. package/plugins/compound-engineering/skills/dspy-ruby/assets/signature-template.rb +221 -0
  145. package/plugins/compound-engineering/skills/dspy-ruby/references/core-concepts.md +674 -0
  146. package/plugins/compound-engineering/skills/dspy-ruby/references/observability.md +366 -0
  147. package/plugins/compound-engineering/skills/dspy-ruby/references/optimization.md +603 -0
  148. package/plugins/compound-engineering/skills/dspy-ruby/references/providers.md +418 -0
  149. package/plugins/compound-engineering/skills/dspy-ruby/references/toolsets.md +502 -0
  150. package/plugins/compound-engineering/skills/every-style-editor/SKILL.md +134 -0
  151. package/plugins/compound-engineering/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
  152. package/plugins/compound-engineering/skills/file-todos/SKILL.md +252 -0
  153. package/plugins/compound-engineering/skills/file-todos/assets/todo-template.md +155 -0
  154. package/plugins/compound-engineering/skills/frontend-design/SKILL.md +42 -0
  155. package/plugins/compound-engineering/skills/gemini-imagegen/SKILL.md +237 -0
  156. package/plugins/compound-engineering/skills/gemini-imagegen/requirements.txt +2 -0
  157. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/compose_images.py +157 -0
  158. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/edit_image.py +144 -0
  159. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/gemini_images.py +263 -0
  160. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/generate_image.py +133 -0
  161. package/plugins/compound-engineering/skills/gemini-imagegen/scripts/multi_turn_chat.py +216 -0
  162. package/plugins/compound-engineering/skills/git-worktree/SKILL.md +302 -0
  163. package/plugins/compound-engineering/skills/git-worktree/scripts/worktree-manager.sh +337 -0
  164. package/plugins/compound-engineering/skills/orchestrating-swarms/SKILL.md +1718 -0
  165. package/plugins/compound-engineering/skills/rclone/SKILL.md +150 -0
  166. package/plugins/compound-engineering/skills/rclone/scripts/check_setup.sh +60 -0
  167. package/plugins/compound-engineering/skills/resolve-pr-parallel/SKILL.md +89 -0
  168. package/plugins/compound-engineering/skills/resolve-pr-parallel/scripts/get-pr-comments +68 -0
  169. package/plugins/compound-engineering/skills/resolve-pr-parallel/scripts/resolve-pr-thread +23 -0
  170. package/plugins/compound-engineering/skills/skill-creator/SKILL.md +210 -0
  171. package/plugins/compound-engineering/skills/skill-creator/scripts/init_skill.py +303 -0
  172. package/plugins/compound-engineering/skills/skill-creator/scripts/package_skill.py +110 -0
  173. package/plugins/compound-engineering/skills/skill-creator/scripts/quick_validate.py +65 -0
  174. package/prompts/deepen-plan.md +549 -0
  175. package/prompts/feature-video.md +341 -0
  176. package/prompts/resolve_todo_parallel.md +36 -0
  177. package/prompts/test-browser.md +342 -0
  178. package/prompts/workflows-brainstorm.md +123 -0
  179. package/prompts/workflows-compound.md +238 -0
  180. package/prompts/workflows-plan.md +550 -0
  181. package/prompts/workflows-review.md +529 -0
  182. package/prompts/workflows-work.md +432 -0
  183. package/skills/agent-browser/SKILL.md +223 -0
  184. package/skills/agent-native-architecture/SKILL.md +435 -0
  185. package/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
  186. package/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
  187. package/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
  188. package/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
  189. package/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
  190. package/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
  191. package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
  192. package/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
  193. package/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
  194. package/skills/agent-native-architecture/references/product-implications.md +443 -0
  195. package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
  196. package/skills/agent-native-architecture/references/self-modification.md +269 -0
  197. package/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
  198. package/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
  199. package/skills/agent-native-reviewer/SKILL.md +260 -0
  200. package/skills/andrew-kane-gem-writer/SKILL.md +184 -0
  201. package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
  202. package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
  203. package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
  204. package/skills/andrew-kane-gem-writer/references/resources.md +119 -0
  205. package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
  206. package/skills/ankane-readme-writer/SKILL.md +63 -0
  207. package/skills/architecture-strategist/SKILL.md +66 -0
  208. package/skills/best-practices-researcher/SKILL.md +125 -0
  209. package/skills/brainstorming/SKILL.md +190 -0
  210. package/skills/bug-reproduction-validator/SKILL.md +81 -0
  211. package/skills/code-simplicity-reviewer/SKILL.md +100 -0
  212. package/skills/compound-docs/SKILL.md +511 -0
  213. package/skills/compound-docs/assets/critical-pattern-template.md +34 -0
  214. package/skills/compound-docs/assets/resolution-template.md +93 -0
  215. package/skills/compound-docs/references/yaml-schema.md +65 -0
  216. package/skills/compound-docs/schema.yaml +176 -0
  217. package/skills/create-agent-skills/SKILL.md +275 -0
  218. package/skills/create-agent-skills/references/api-security.md +226 -0
  219. package/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
  220. package/skills/create-agent-skills/references/best-practices.md +404 -0
  221. package/skills/create-agent-skills/references/common-patterns.md +595 -0
  222. package/skills/create-agent-skills/references/core-principles.md +437 -0
  223. package/skills/create-agent-skills/references/executable-code.md +175 -0
  224. package/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
  225. package/skills/create-agent-skills/references/official-spec.md +134 -0
  226. package/skills/create-agent-skills/references/recommended-structure.md +168 -0
  227. package/skills/create-agent-skills/references/skill-structure.md +152 -0
  228. package/skills/create-agent-skills/references/using-scripts.md +113 -0
  229. package/skills/create-agent-skills/references/using-templates.md +112 -0
  230. package/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
  231. package/skills/create-agent-skills/templates/router-skill.md +73 -0
  232. package/skills/create-agent-skills/templates/simple-skill.md +33 -0
  233. package/skills/create-agent-skills/workflows/add-reference.md +96 -0
  234. package/skills/create-agent-skills/workflows/add-script.md +93 -0
  235. package/skills/create-agent-skills/workflows/add-template.md +74 -0
  236. package/skills/create-agent-skills/workflows/add-workflow.md +120 -0
  237. package/skills/create-agent-skills/workflows/audit-skill.md +138 -0
  238. package/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
  239. package/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
  240. package/skills/create-agent-skills/workflows/get-guidance.md +121 -0
  241. package/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
  242. package/skills/create-agent-skills/workflows/verify-skill.md +204 -0
  243. package/skills/data-integrity-guardian/SKILL.md +84 -0
  244. package/skills/data-migration-expert/SKILL.md +111 -0
  245. package/skills/deployment-verification-agent/SKILL.md +173 -0
  246. package/skills/design-implementation-reviewer/SKILL.md +107 -0
  247. package/skills/design-iterator/SKILL.md +222 -0
  248. package/skills/dhh-rails-reviewer/SKILL.md +65 -0
  249. package/skills/dhh-rails-style/SKILL.md +185 -0
  250. package/skills/dhh-rails-style/references/architecture.md +653 -0
  251. package/skills/dhh-rails-style/references/controllers.md +303 -0
  252. package/skills/dhh-rails-style/references/frontend.md +510 -0
  253. package/skills/dhh-rails-style/references/gems.md +266 -0
  254. package/skills/dhh-rails-style/references/models.md +359 -0
  255. package/skills/dhh-rails-style/references/testing.md +338 -0
  256. package/skills/document-review/SKILL.md +87 -0
  257. package/skills/dspy-ruby/SKILL.md +737 -0
  258. package/skills/dspy-ruby/assets/config-template.rb +187 -0
  259. package/skills/dspy-ruby/assets/module-template.rb +300 -0
  260. package/skills/dspy-ruby/assets/signature-template.rb +221 -0
  261. package/skills/dspy-ruby/references/core-concepts.md +674 -0
  262. package/skills/dspy-ruby/references/observability.md +366 -0
  263. package/skills/dspy-ruby/references/optimization.md +603 -0
  264. package/skills/dspy-ruby/references/providers.md +418 -0
  265. package/skills/dspy-ruby/references/toolsets.md +502 -0
  266. package/skills/every-style-editor/SKILL.md +134 -0
  267. package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
  268. package/skills/every-style-editor-2/SKILL.md +62 -0
  269. package/skills/figma-design-sync/SKILL.md +188 -0
  270. package/skills/file-todos/SKILL.md +252 -0
  271. package/skills/file-todos/assets/todo-template.md +155 -0
  272. package/skills/framework-docs-researcher/SKILL.md +105 -0
  273. package/skills/frontend-design/SKILL.md +42 -0
  274. package/skills/gemini-imagegen/SKILL.md +237 -0
  275. package/skills/gemini-imagegen/requirements.txt +2 -0
  276. package/skills/gemini-imagegen/scripts/compose_images.py +157 -0
  277. package/skills/gemini-imagegen/scripts/edit_image.py +144 -0
  278. package/skills/gemini-imagegen/scripts/gemini_images.py +263 -0
  279. package/skills/gemini-imagegen/scripts/generate_image.py +133 -0
  280. package/skills/gemini-imagegen/scripts/multi_turn_chat.py +216 -0
  281. package/skills/git-history-analyzer/SKILL.md +58 -0
  282. package/skills/git-worktree/SKILL.md +302 -0
  283. package/skills/git-worktree/scripts/worktree-manager.sh +337 -0
  284. package/skills/julik-frontend-races-reviewer/SKILL.md +220 -0
  285. package/skills/kieran-python-reviewer/SKILL.md +132 -0
  286. package/skills/kieran-rails-reviewer/SKILL.md +114 -0
  287. package/skills/kieran-typescript-reviewer/SKILL.md +123 -0
  288. package/skills/learnings-researcher/SKILL.md +263 -0
  289. package/skills/lint/SKILL.md +14 -0
  290. package/skills/orchestrating-swarms/SKILL.md +1718 -0
  291. package/skills/pattern-recognition-specialist/SKILL.md +71 -0
  292. package/skills/performance-oracle/SKILL.md +136 -0
  293. package/skills/pr-comment-resolver/SKILL.md +82 -0
  294. package/skills/rclone/SKILL.md +150 -0
  295. package/skills/rclone/scripts/check_setup.sh +60 -0
  296. package/skills/repo-research-analyst/SKILL.md +134 -0
  297. package/skills/resolve_pr_parallel/SKILL.md +89 -0
  298. package/skills/resolve_pr_parallel/scripts/get-pr-comments +68 -0
  299. package/skills/resolve_pr_parallel/scripts/resolve-pr-thread +23 -0
  300. package/skills/schema-drift-detector/SKILL.md +153 -0
  301. package/skills/security-sentinel/SKILL.md +113 -0
  302. package/skills/skill-creator/SKILL.md +210 -0
  303. package/skills/skill-creator/scripts/init_skill.py +303 -0
  304. package/skills/skill-creator/scripts/package_skill.py +110 -0
  305. package/skills/skill-creator/scripts/quick_validate.py +65 -0
  306. package/skills/spec-flow-analyzer/SKILL.md +133 -0
  307. package/src/commands/convert.ts +183 -0
  308. package/src/commands/install.ts +273 -0
  309. package/src/commands/list.ts +37 -0
  310. package/src/commands/sync.ts +89 -0
  311. package/src/converters/claude-to-codex.ts +182 -0
  312. package/src/converters/claude-to-opencode.ts +395 -0
  313. package/src/converters/claude-to-pi.ts +205 -0
  314. package/src/index.ts +22 -0
  315. package/src/parsers/claude-home.ts +65 -0
  316. package/src/parsers/claude.ts +252 -0
  317. package/src/sync/codex.ts +92 -0
  318. package/src/sync/opencode.ts +75 -0
  319. package/src/sync/pi.ts +88 -0
  320. package/src/targets/codex.ts +96 -0
  321. package/src/targets/index.ts +38 -0
  322. package/src/targets/opencode.ts +57 -0
  323. package/src/targets/pi.ts +131 -0
  324. package/src/templates/pi/compat-extension.ts +452 -0
  325. package/src/types/claude.ts +90 -0
  326. package/src/types/codex.ts +23 -0
  327. package/src/types/opencode.ts +54 -0
  328. package/src/types/pi.ts +40 -0
  329. package/src/utils/codex-agents.ts +64 -0
  330. package/src/utils/files.ts +77 -0
  331. package/src/utils/frontmatter.ts +65 -0
  332. package/src/utils/symlink.ts +43 -0
@@ -0,0 +1,182 @@
1
+ import { formatFrontmatter } from "../utils/frontmatter"
2
+ import type { ClaudeAgent, ClaudeCommand, ClaudePlugin } from "../types/claude"
3
+ import type { CodexBundle, CodexGeneratedSkill } from "../types/codex"
4
+ import type { ClaudeToOpenCodeOptions } from "./claude-to-opencode"
5
+
6
+ export type ClaudeToCodexOptions = ClaudeToOpenCodeOptions
7
+
8
+ const CODEX_DESCRIPTION_MAX_LENGTH = 1024
9
+
10
+ export function convertClaudeToCodex(
11
+ plugin: ClaudePlugin,
12
+ _options: ClaudeToCodexOptions,
13
+ ): CodexBundle {
14
+ const promptNames = new Set<string>()
15
+ const skillDirs = plugin.skills.map((skill) => ({
16
+ name: skill.name,
17
+ sourceDir: skill.sourceDir,
18
+ }))
19
+
20
+ const usedSkillNames = new Set<string>(skillDirs.map((skill) => normalizeName(skill.name)))
21
+ const commandSkills: CodexGeneratedSkill[] = []
22
+ const invocableCommands = plugin.commands.filter((command) => !command.disableModelInvocation)
23
+ const prompts = invocableCommands.map((command) => {
24
+ const promptName = uniqueName(normalizeName(command.name), promptNames)
25
+ const commandSkill = convertCommandSkill(command, usedSkillNames)
26
+ commandSkills.push(commandSkill)
27
+ const content = renderPrompt(command, commandSkill.name)
28
+ return { name: promptName, content }
29
+ })
30
+
31
+ const agentSkills = plugin.agents.map((agent) => convertAgent(agent, usedSkillNames))
32
+ const generatedSkills = [...commandSkills, ...agentSkills]
33
+
34
+ return {
35
+ prompts,
36
+ skillDirs,
37
+ generatedSkills,
38
+ mcpServers: plugin.mcpServers,
39
+ }
40
+ }
41
+
42
+ function convertAgent(agent: ClaudeAgent, usedNames: Set<string>): CodexGeneratedSkill {
43
+ const name = uniqueName(normalizeName(agent.name), usedNames)
44
+ const description = sanitizeDescription(
45
+ agent.description ?? `Converted from Claude agent ${agent.name}`,
46
+ )
47
+ const frontmatter: Record<string, unknown> = { name, description }
48
+
49
+ let body = agent.body.trim()
50
+ if (agent.capabilities && agent.capabilities.length > 0) {
51
+ const capabilities = agent.capabilities.map((capability) => `- ${capability}`).join("\n")
52
+ body = `## Capabilities\n${capabilities}\n\n${body}`.trim()
53
+ }
54
+ if (body.length === 0) {
55
+ body = `Instructions converted from the ${agent.name} agent.`
56
+ }
57
+
58
+ const content = formatFrontmatter(frontmatter, body)
59
+ return { name, content }
60
+ }
61
+
62
+ function convertCommandSkill(command: ClaudeCommand, usedNames: Set<string>): CodexGeneratedSkill {
63
+ const name = uniqueName(normalizeName(command.name), usedNames)
64
+ const frontmatter: Record<string, unknown> = {
65
+ name,
66
+ description: sanitizeDescription(
67
+ command.description ?? `Converted from Claude command ${command.name}`,
68
+ ),
69
+ }
70
+ const sections: string[] = []
71
+ if (command.argumentHint) {
72
+ sections.push(`## Arguments\n${command.argumentHint}`)
73
+ }
74
+ if (command.allowedTools && command.allowedTools.length > 0) {
75
+ sections.push(`## Allowed tools\n${command.allowedTools.map((tool) => `- ${tool}`).join("\n")}`)
76
+ }
77
+ // Transform Task agent calls to Codex skill references
78
+ const transformedBody = transformTaskCalls(command.body.trim())
79
+ sections.push(transformedBody)
80
+ const body = sections.filter(Boolean).join("\n\n").trim()
81
+ const content = formatFrontmatter(frontmatter, body.length > 0 ? body : command.body)
82
+ return { name, content }
83
+ }
84
+
85
+ /**
86
+ * Transform Claude Code content to Codex-compatible content.
87
+ *
88
+ * Handles multiple syntax differences:
89
+ * 1. Task agent calls: Task agent-name(args) → Use the $agent-name skill to: args
90
+ * 2. Slash commands: /command-name → /prompts:command-name
91
+ * 3. Agent references: @agent-name → $agent-name skill
92
+ *
93
+ * This bridges the gap since Claude Code and Codex have different syntax
94
+ * for invoking commands, agents, and skills.
95
+ */
96
+ function transformContentForCodex(body: string): string {
97
+ let result = body
98
+
99
+ // 1. Transform Task agent calls
100
+ // Match: Task repo-research-analyst(feature_description)
101
+ // Match: - Task learnings-researcher(args)
102
+ const taskPattern = /^(\s*-?\s*)Task\s+([a-z][a-z0-9-]*)\(([^)]+)\)/gm
103
+ result = result.replace(taskPattern, (_match, prefix: string, agentName: string, args: string) => {
104
+ const skillName = normalizeName(agentName)
105
+ const trimmedArgs = args.trim()
106
+ return `${prefix}Use the $${skillName} skill to: ${trimmedArgs}`
107
+ })
108
+
109
+ // 2. Transform slash command references
110
+ // Match: /command-name or /workflows:command but NOT /path/to/file or URLs
111
+ // Look for slash commands in contexts like "Run /command", "use /command", etc.
112
+ // Avoid matching file paths (contain multiple slashes) or URLs (contain ://)
113
+ const slashCommandPattern = /(?<![:\w])\/([a-z][a-z0-9_:-]*?)(?=[\s,."')\]}`]|$)/gi
114
+ result = result.replace(slashCommandPattern, (match, commandName: string) => {
115
+ // Skip if it looks like a file path (contains /)
116
+ if (commandName.includes('/')) return match
117
+ // Skip common non-command patterns
118
+ if (['dev', 'tmp', 'etc', 'usr', 'var', 'bin', 'home'].includes(commandName)) return match
119
+ // Transform to Codex prompt syntax
120
+ const normalizedName = normalizeName(commandName)
121
+ return `/prompts:${normalizedName}`
122
+ })
123
+
124
+ // 3. Transform @agent-name references
125
+ // Match: @agent-name in text (not emails)
126
+ const agentRefPattern = /@([a-z][a-z0-9-]*-(?:agent|reviewer|researcher|analyst|specialist|oracle|sentinel|guardian|strategist))/gi
127
+ result = result.replace(agentRefPattern, (_match, agentName: string) => {
128
+ const skillName = normalizeName(agentName)
129
+ return `$${skillName} skill`
130
+ })
131
+
132
+ return result
133
+ }
134
+
135
+ // Alias for backward compatibility
136
+ const transformTaskCalls = transformContentForCodex
137
+
138
+ function renderPrompt(command: ClaudeCommand, skillName: string): string {
139
+ const frontmatter: Record<string, unknown> = {
140
+ description: command.description,
141
+ "argument-hint": command.argumentHint,
142
+ }
143
+ const instructions = `Use the $${skillName} skill for this command and follow its instructions.`
144
+ // Transform Task calls in prompt body too (not just skill body)
145
+ const transformedBody = transformTaskCalls(command.body)
146
+ const body = [instructions, "", transformedBody].join("\n").trim()
147
+ return formatFrontmatter(frontmatter, body)
148
+ }
149
+
150
+ function normalizeName(value: string): string {
151
+ const trimmed = value.trim()
152
+ if (!trimmed) return "item"
153
+ const normalized = trimmed
154
+ .toLowerCase()
155
+ .replace(/[\\/]+/g, "-")
156
+ .replace(/[:\s]+/g, "-")
157
+ .replace(/[^a-z0-9_-]+/g, "-")
158
+ .replace(/-+/g, "-")
159
+ .replace(/^-+|-+$/g, "")
160
+ return normalized || "item"
161
+ }
162
+
163
+ function sanitizeDescription(value: string, maxLength = CODEX_DESCRIPTION_MAX_LENGTH): string {
164
+ const normalized = value.replace(/\s+/g, " ").trim()
165
+ if (normalized.length <= maxLength) return normalized
166
+ const ellipsis = "..."
167
+ return normalized.slice(0, Math.max(0, maxLength - ellipsis.length)).trimEnd() + ellipsis
168
+ }
169
+
170
+ function uniqueName(base: string, used: Set<string>): string {
171
+ if (!used.has(base)) {
172
+ used.add(base)
173
+ return base
174
+ }
175
+ let index = 2
176
+ while (used.has(`${base}-${index}`)) {
177
+ index += 1
178
+ }
179
+ const name = `${base}-${index}`
180
+ used.add(name)
181
+ return name
182
+ }
@@ -0,0 +1,395 @@
1
+ import { formatFrontmatter } from "../utils/frontmatter"
2
+ import type {
3
+ ClaudeAgent,
4
+ ClaudeCommand,
5
+ ClaudeHooks,
6
+ ClaudePlugin,
7
+ ClaudeMcpServer,
8
+ } from "../types/claude"
9
+ import type {
10
+ OpenCodeBundle,
11
+ OpenCodeCommandConfig,
12
+ OpenCodeConfig,
13
+ OpenCodeMcpServer,
14
+ } from "../types/opencode"
15
+
16
+ export type PermissionMode = "none" | "broad" | "from-commands"
17
+
18
+ export type ClaudeToOpenCodeOptions = {
19
+ agentMode: "primary" | "subagent"
20
+ inferTemperature: boolean
21
+ permissions: PermissionMode
22
+ }
23
+
24
+ const TOOL_MAP: Record<string, string> = {
25
+ bash: "bash",
26
+ read: "read",
27
+ write: "write",
28
+ edit: "edit",
29
+ grep: "grep",
30
+ glob: "glob",
31
+ list: "list",
32
+ webfetch: "webfetch",
33
+ skill: "skill",
34
+ patch: "patch",
35
+ task: "task",
36
+ question: "question",
37
+ todowrite: "todowrite",
38
+ todoread: "todoread",
39
+ }
40
+
41
+ type HookEventMapping = {
42
+ events: string[]
43
+ type: "tool" | "session" | "permission" | "message"
44
+ requireError?: boolean
45
+ note?: string
46
+ }
47
+
48
+ const HOOK_EVENT_MAP: Record<string, HookEventMapping> = {
49
+ PreToolUse: { events: ["tool.execute.before"], type: "tool" },
50
+ PostToolUse: { events: ["tool.execute.after"], type: "tool" },
51
+ PostToolUseFailure: { events: ["tool.execute.after"], type: "tool", requireError: true, note: "Claude PostToolUseFailure" },
52
+ SessionStart: { events: ["session.created"], type: "session" },
53
+ SessionEnd: { events: ["session.deleted"], type: "session" },
54
+ Stop: { events: ["session.idle"], type: "session" },
55
+ PreCompact: { events: ["experimental.session.compacting"], type: "session" },
56
+ PermissionRequest: { events: ["permission.requested", "permission.replied"], type: "permission", note: "Claude PermissionRequest" },
57
+ UserPromptSubmit: { events: ["message.created", "message.updated"], type: "message", note: "Claude UserPromptSubmit" },
58
+ Notification: { events: ["message.updated"], type: "message", note: "Claude Notification" },
59
+ Setup: { events: ["session.created"], type: "session", note: "Claude Setup" },
60
+ SubagentStart: { events: ["message.updated"], type: "message", note: "Claude SubagentStart" },
61
+ SubagentStop: { events: ["message.updated"], type: "message", note: "Claude SubagentStop" },
62
+ }
63
+
64
+ export function convertClaudeToOpenCode(
65
+ plugin: ClaudePlugin,
66
+ options: ClaudeToOpenCodeOptions,
67
+ ): OpenCodeBundle {
68
+ const agentFiles = plugin.agents.map((agent) => convertAgent(agent, options))
69
+ const commandMap = convertCommands(plugin.commands)
70
+ const mcp = plugin.mcpServers ? convertMcp(plugin.mcpServers) : undefined
71
+ const plugins = plugin.hooks ? [convertHooks(plugin.hooks)] : []
72
+
73
+ const config: OpenCodeConfig = {
74
+ $schema: "https://opencode.ai/config.json",
75
+ command: Object.keys(commandMap).length > 0 ? commandMap : undefined,
76
+ mcp: mcp && Object.keys(mcp).length > 0 ? mcp : undefined,
77
+ }
78
+
79
+ applyPermissions(config, plugin.commands, options.permissions)
80
+
81
+ return {
82
+ config,
83
+ agents: agentFiles,
84
+ plugins,
85
+ skillDirs: plugin.skills.map((skill) => ({ sourceDir: skill.sourceDir, name: skill.name })),
86
+ }
87
+ }
88
+
89
+ function convertAgent(agent: ClaudeAgent, options: ClaudeToOpenCodeOptions) {
90
+ const frontmatter: Record<string, unknown> = {
91
+ description: agent.description,
92
+ mode: options.agentMode,
93
+ }
94
+
95
+ if (agent.model && agent.model !== "inherit") {
96
+ frontmatter.model = normalizeModel(agent.model)
97
+ }
98
+
99
+ if (options.inferTemperature) {
100
+ const temperature = inferTemperature(agent)
101
+ if (temperature !== undefined) {
102
+ frontmatter.temperature = temperature
103
+ }
104
+ }
105
+
106
+ const content = formatFrontmatter(frontmatter, agent.body)
107
+
108
+ return {
109
+ name: agent.name,
110
+ content,
111
+ }
112
+ }
113
+
114
+ function convertCommands(commands: ClaudeCommand[]): Record<string, OpenCodeCommandConfig> {
115
+ const result: Record<string, OpenCodeCommandConfig> = {}
116
+ for (const command of commands) {
117
+ if (command.disableModelInvocation) continue
118
+ const entry: OpenCodeCommandConfig = {
119
+ description: command.description,
120
+ template: command.body,
121
+ }
122
+ if (command.model && command.model !== "inherit") {
123
+ entry.model = normalizeModel(command.model)
124
+ }
125
+ result[command.name] = entry
126
+ }
127
+ return result
128
+ }
129
+
130
+ function convertMcp(servers: Record<string, ClaudeMcpServer>): Record<string, OpenCodeMcpServer> {
131
+ const result: Record<string, OpenCodeMcpServer> = {}
132
+ for (const [name, server] of Object.entries(servers)) {
133
+ if (server.command) {
134
+ result[name] = {
135
+ type: "local",
136
+ command: [server.command, ...(server.args ?? [])],
137
+ environment: server.env,
138
+ enabled: true,
139
+ }
140
+ continue
141
+ }
142
+
143
+ if (server.url) {
144
+ result[name] = {
145
+ type: "remote",
146
+ url: server.url,
147
+ headers: server.headers,
148
+ enabled: true,
149
+ }
150
+ }
151
+ }
152
+ return result
153
+ }
154
+
155
+ function convertHooks(hooks: ClaudeHooks) {
156
+ const handlerBlocks: string[] = []
157
+ const hookMap = hooks.hooks
158
+ const unmappedEvents: string[] = []
159
+
160
+ for (const [eventName, matchers] of Object.entries(hookMap)) {
161
+ const mapping = HOOK_EVENT_MAP[eventName]
162
+ if (!mapping) {
163
+ unmappedEvents.push(eventName)
164
+ continue
165
+ }
166
+ if (matchers.length === 0) continue
167
+ for (const event of mapping.events) {
168
+ handlerBlocks.push(
169
+ renderHookHandlers(event, matchers, {
170
+ useToolMatcher: mapping.type === "tool" || mapping.type === "permission",
171
+ requireError: mapping.requireError ?? false,
172
+ note: mapping.note,
173
+ }),
174
+ )
175
+ }
176
+ }
177
+
178
+ const unmappedComment = unmappedEvents.length > 0
179
+ ? `// Unmapped Claude hook events: ${unmappedEvents.join(", ")}\n`
180
+ : ""
181
+
182
+ const content = `${unmappedComment}import type { Plugin } from "@opencode-ai/plugin"\n\nexport const ConvertedHooks: Plugin = async ({ $ }) => {\n return {\n${handlerBlocks.join(",\n")}\n }\n}\n\nexport default ConvertedHooks\n`
183
+
184
+ return {
185
+ name: "converted-hooks.ts",
186
+ content,
187
+ }
188
+ }
189
+
190
+ function renderHookHandlers(
191
+ event: string,
192
+ matchers: ClaudeHooks["hooks"][string],
193
+ options: { useToolMatcher: boolean; requireError: boolean; note?: string },
194
+ ) {
195
+ const statements: string[] = []
196
+ for (const matcher of matchers) {
197
+ statements.push(...renderHookStatements(matcher, options.useToolMatcher))
198
+ }
199
+ const rendered = statements.map((line) => ` ${line}`).join("\n")
200
+ const wrapped = options.requireError
201
+ ? ` if (input?.error) {\n${statements.map((line) => ` ${line}`).join("\n")}\n }`
202
+ : rendered
203
+ const note = options.note ? ` // ${options.note}\n` : ""
204
+ return ` "${event}": async (input) => {\n${note}${wrapped}\n }`
205
+ }
206
+
207
+ function renderHookStatements(
208
+ matcher: ClaudeHooks["hooks"][string][number],
209
+ useToolMatcher: boolean,
210
+ ): string[] {
211
+ if (!matcher.hooks || matcher.hooks.length === 0) return []
212
+ const tools = matcher.matcher
213
+ ? matcher.matcher
214
+ .split("|")
215
+ .map((tool) => tool.trim().toLowerCase())
216
+ .filter(Boolean)
217
+ : []
218
+
219
+ const useMatcher = useToolMatcher && tools.length > 0 && !tools.includes("*")
220
+ const condition = useMatcher
221
+ ? tools.map((tool) => `input.tool === "${tool}"`).join(" || ")
222
+ : null
223
+ const statements: string[] = []
224
+
225
+ for (const hook of matcher.hooks) {
226
+ if (hook.type === "command") {
227
+ if (condition) {
228
+ statements.push(`if (${condition}) { await $\`${hook.command}\` }`)
229
+ } else {
230
+ statements.push(`await $\`${hook.command}\``)
231
+ }
232
+ if (hook.timeout) {
233
+ statements.push(`// timeout: ${hook.timeout}s (not enforced)`)
234
+ }
235
+ continue
236
+ }
237
+ if (hook.type === "prompt") {
238
+ statements.push(`// Prompt hook for ${matcher.matcher ?? "*"}: ${hook.prompt.replace(/\n/g, " ")}`)
239
+ continue
240
+ }
241
+ statements.push(`// Agent hook for ${matcher.matcher ?? "*"}: ${hook.agent}`)
242
+ }
243
+
244
+ return statements
245
+ }
246
+
247
+ function normalizeModel(model: string): string {
248
+ if (model.includes("/")) return model
249
+ if (/^claude-/.test(model)) return `anthropic/${model}`
250
+ if (/^(gpt-|o1-|o3-)/.test(model)) return `openai/${model}`
251
+ if (/^gemini-/.test(model)) return `google/${model}`
252
+ return `anthropic/${model}`
253
+ }
254
+
255
+ function inferTemperature(agent: ClaudeAgent): number | undefined {
256
+ const sample = `${agent.name} ${agent.description ?? ""}`.toLowerCase()
257
+ if (/(review|audit|security|sentinel|oracle|lint|verification|guardian)/.test(sample)) {
258
+ return 0.1
259
+ }
260
+ if (/(plan|planning|architecture|strategist|analysis|research)/.test(sample)) {
261
+ return 0.2
262
+ }
263
+ if (/(doc|readme|changelog|editor|writer)/.test(sample)) {
264
+ return 0.3
265
+ }
266
+ if (/(brainstorm|creative|ideate|design|concept)/.test(sample)) {
267
+ return 0.6
268
+ }
269
+ return 0.3
270
+ }
271
+
272
+ function applyPermissions(
273
+ config: OpenCodeConfig,
274
+ commands: ClaudeCommand[],
275
+ mode: PermissionMode,
276
+ ) {
277
+ if (mode === "none") return
278
+
279
+ const sourceTools = [
280
+ "read",
281
+ "write",
282
+ "edit",
283
+ "bash",
284
+ "grep",
285
+ "glob",
286
+ "list",
287
+ "webfetch",
288
+ "skill",
289
+ "patch",
290
+ "task",
291
+ "question",
292
+ "todowrite",
293
+ "todoread",
294
+ ]
295
+ let enabled = new Set<string>()
296
+ const patterns: Record<string, Set<string>> = {}
297
+
298
+ if (mode === "broad") {
299
+ enabled = new Set(sourceTools)
300
+ } else {
301
+ for (const command of commands) {
302
+ if (!command.allowedTools) continue
303
+ for (const tool of command.allowedTools) {
304
+ const parsed = parseToolSpec(tool)
305
+ if (!parsed.tool) continue
306
+ enabled.add(parsed.tool)
307
+ if (parsed.pattern) {
308
+ const normalizedPattern = normalizePattern(parsed.tool, parsed.pattern)
309
+ if (!patterns[parsed.tool]) patterns[parsed.tool] = new Set()
310
+ patterns[parsed.tool].add(normalizedPattern)
311
+ }
312
+ }
313
+ }
314
+ }
315
+
316
+ const permission: Record<string, "allow" | "deny"> = {}
317
+ const tools: Record<string, boolean> = {}
318
+
319
+ for (const tool of sourceTools) {
320
+ tools[tool] = mode === "broad" ? true : enabled.has(tool)
321
+ }
322
+
323
+ if (mode === "broad") {
324
+ for (const tool of sourceTools) {
325
+ permission[tool] = "allow"
326
+ }
327
+ } else {
328
+ for (const tool of sourceTools) {
329
+ const toolPatterns = patterns[tool]
330
+ if (toolPatterns && toolPatterns.size > 0) {
331
+ const patternPermission: Record<string, "allow" | "deny"> = { "*": "deny" }
332
+ for (const pattern of toolPatterns) {
333
+ patternPermission[pattern] = "allow"
334
+ }
335
+ ;(permission as Record<string, typeof patternPermission>)[tool] = patternPermission
336
+ } else {
337
+ permission[tool] = enabled.has(tool) ? "allow" : "deny"
338
+ }
339
+ }
340
+ }
341
+
342
+ if (mode !== "broad") {
343
+ for (const [tool, toolPatterns] of Object.entries(patterns)) {
344
+ if (!toolPatterns || toolPatterns.size === 0) continue
345
+ const patternPermission: Record<string, "allow" | "deny"> = { "*": "deny" }
346
+ for (const pattern of toolPatterns) {
347
+ patternPermission[pattern] = "allow"
348
+ }
349
+ ;(permission as Record<string, typeof patternPermission>)[tool] = patternPermission
350
+ }
351
+ }
352
+
353
+ if (enabled.has("write") || enabled.has("edit")) {
354
+ if (typeof permission.edit === "string") permission.edit = "allow"
355
+ if (typeof permission.write === "string") permission.write = "allow"
356
+ }
357
+ if (patterns.write || patterns.edit) {
358
+ const combined = new Set<string>()
359
+ for (const pattern of patterns.write ?? []) combined.add(pattern)
360
+ for (const pattern of patterns.edit ?? []) combined.add(pattern)
361
+ const combinedPermission: Record<string, "allow" | "deny"> = { "*": "deny" }
362
+ for (const pattern of combined) {
363
+ combinedPermission[pattern] = "allow"
364
+ }
365
+ ;(permission as Record<string, typeof combinedPermission>).edit = combinedPermission
366
+ ;(permission as Record<string, typeof combinedPermission>).write = combinedPermission
367
+ }
368
+
369
+ config.permission = permission
370
+ config.tools = tools
371
+ }
372
+
373
+ function normalizeTool(raw: string): string | null {
374
+ return parseToolSpec(raw).tool
375
+ }
376
+
377
+ function parseToolSpec(raw: string): { tool: string | null; pattern?: string } {
378
+ const trimmed = raw.trim()
379
+ if (!trimmed) return { tool: null }
380
+ const [namePart, patternPart] = trimmed.split("(", 2)
381
+ const name = namePart.trim().toLowerCase()
382
+ const tool = TOOL_MAP[name] ?? null
383
+ if (!patternPart) return { tool }
384
+ const normalizedPattern = patternPart.endsWith(")")
385
+ ? patternPart.slice(0, -1).trim()
386
+ : patternPart.trim()
387
+ return { tool, pattern: normalizedPattern }
388
+ }
389
+
390
+ function normalizePattern(tool: string, pattern: string): string {
391
+ if (tool === "bash") {
392
+ return pattern.replace(/:/g, " ").trim()
393
+ }
394
+ return pattern
395
+ }