@lucasi/vibes 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 (359) hide show
  1. package/AGENTS.md +162 -0
  2. package/MIGRATION.md +368 -0
  3. package/README.md +44 -0
  4. package/bin/setup.js +127 -0
  5. package/commands/build-fix.md +56 -0
  6. package/commands/checkpoint.md +67 -0
  7. package/commands/code-review.md +68 -0
  8. package/commands/e2e.md +105 -0
  9. package/commands/eval.md +88 -0
  10. package/commands/evolve.md +36 -0
  11. package/commands/go-build.md +87 -0
  12. package/commands/go-review.md +71 -0
  13. package/commands/go-test.md +131 -0
  14. package/commands/harness-audit.md +73 -0
  15. package/commands/instinct-export.md +93 -0
  16. package/commands/instinct-import.md +88 -0
  17. package/commands/instinct-status.md +29 -0
  18. package/commands/learn.md +61 -0
  19. package/commands/loop-start.md +32 -0
  20. package/commands/loop-status.md +24 -0
  21. package/commands/model-route.md +26 -0
  22. package/commands/orchestrate.md +88 -0
  23. package/commands/plan.md +25 -0
  24. package/commands/projects.md +23 -0
  25. package/commands/promote.md +23 -0
  26. package/commands/quality-gate.md +29 -0
  27. package/commands/refactor-clean.md +102 -0
  28. package/commands/rust-build.md +78 -0
  29. package/commands/rust-review.md +65 -0
  30. package/commands/rust-test.md +104 -0
  31. package/commands/security.md +89 -0
  32. package/commands/setup-pm.md +67 -0
  33. package/commands/skill-create.md +117 -0
  34. package/commands/tdd.md +67 -0
  35. package/commands/test-coverage.md +80 -0
  36. package/commands/update-codemaps.md +81 -0
  37. package/commands/update-docs.md +67 -0
  38. package/commands/verify.md +67 -0
  39. package/instructions/INSTRUCTIONS.md +337 -0
  40. package/opencode.json +466 -0
  41. package/package.json +27 -0
  42. package/prompts/agents/architect.txt +175 -0
  43. package/prompts/agents/build-error-resolver.txt +233 -0
  44. package/prompts/agents/code-reviewer.txt +103 -0
  45. package/prompts/agents/cpp-build-resolver.txt +81 -0
  46. package/prompts/agents/cpp-reviewer.txt +65 -0
  47. package/prompts/agents/database-reviewer.txt +247 -0
  48. package/prompts/agents/doc-updater.txt +192 -0
  49. package/prompts/agents/docs-lookup.txt +57 -0
  50. package/prompts/agents/e2e-runner.txt +305 -0
  51. package/prompts/agents/go-build-resolver.txt +325 -0
  52. package/prompts/agents/go-reviewer.txt +241 -0
  53. package/prompts/agents/harness-optimizer.txt +27 -0
  54. package/prompts/agents/java-build-resolver.txt +123 -0
  55. package/prompts/agents/java-reviewer.txt +97 -0
  56. package/prompts/agents/kotlin-build-resolver.txt +120 -0
  57. package/prompts/agents/kotlin-reviewer.txt +127 -0
  58. package/prompts/agents/loop-operator.txt +39 -0
  59. package/prompts/agents/planner.txt +113 -0
  60. package/prompts/agents/python-reviewer.txt +85 -0
  61. package/prompts/agents/refactor-cleaner.txt +241 -0
  62. package/prompts/agents/rust-build-resolver.txt +93 -0
  63. package/prompts/agents/rust-reviewer.txt +61 -0
  64. package/prompts/agents/security-reviewer.txt +207 -0
  65. package/prompts/agents/tdd-guide.txt +216 -0
  66. package/skills/agent-eval/SKILL.md +145 -0
  67. package/skills/agent-harness-construction/SKILL.md +73 -0
  68. package/skills/agent-introspection-debugging/SKILL.md +153 -0
  69. package/skills/agent-payment-x402/SKILL.md +178 -0
  70. package/skills/agent-sort/SKILL.md +215 -0
  71. package/skills/agentic-engineering/SKILL.md +63 -0
  72. package/skills/ai-first-engineering/SKILL.md +51 -0
  73. package/skills/ai-regression-testing/SKILL.md +385 -0
  74. package/skills/android-clean-architecture/SKILL.md +339 -0
  75. package/skills/api-connector-builder/SKILL.md +120 -0
  76. package/skills/api-design/SKILL.md +523 -0
  77. package/skills/architecture-decision-records/SKILL.md +179 -0
  78. package/skills/article-writing/SKILL.md +79 -0
  79. package/skills/automation-audit-ops/SKILL.md +142 -0
  80. package/skills/autonomous-agent-harness/SKILL.md +267 -0
  81. package/skills/autonomous-loops/SKILL.md +610 -0
  82. package/skills/backend-patterns/SKILL.md +598 -0
  83. package/skills/benchmark/SKILL.md +93 -0
  84. package/skills/blueprint/SKILL.md +105 -0
  85. package/skills/brand-voice/SKILL.md +97 -0
  86. package/skills/brand-voice/references/voice-profile-schema.md +55 -0
  87. package/skills/browser-qa/SKILL.md +87 -0
  88. package/skills/bun-runtime/SKILL.md +84 -0
  89. package/skills/canary-watch/SKILL.md +99 -0
  90. package/skills/carrier-relationship-management/SKILL.md +212 -0
  91. package/skills/ck/SKILL.md +147 -0
  92. package/skills/ck/commands/forget.mjs +44 -0
  93. package/skills/ck/commands/info.mjs +24 -0
  94. package/skills/ck/commands/init.mjs +143 -0
  95. package/skills/ck/commands/list.mjs +40 -0
  96. package/skills/ck/commands/migrate.mjs +202 -0
  97. package/skills/ck/commands/resume.mjs +36 -0
  98. package/skills/ck/commands/save.mjs +210 -0
  99. package/skills/ck/commands/shared.mjs +387 -0
  100. package/skills/ck/hooks/session-start.mjs +224 -0
  101. package/skills/claude-api/SKILL.md +337 -0
  102. package/skills/claude-devfleet/SKILL.md +103 -0
  103. package/skills/click-path-audit/SKILL.md +244 -0
  104. package/skills/clickhouse-io/SKILL.md +439 -0
  105. package/skills/code-tour/SKILL.md +236 -0
  106. package/skills/codebase-onboarding/SKILL.md +233 -0
  107. package/skills/coding-standards/SKILL.md +549 -0
  108. package/skills/compose-multiplatform-patterns/SKILL.md +299 -0
  109. package/skills/configure-ecc/SKILL.md +367 -0
  110. package/skills/connections-optimizer/SKILL.md +189 -0
  111. package/skills/content-engine/SKILL.md +131 -0
  112. package/skills/content-hash-cache-pattern/SKILL.md +161 -0
  113. package/skills/context-budget/SKILL.md +135 -0
  114. package/skills/continuous-agent-loop/SKILL.md +45 -0
  115. package/skills/continuous-learning/SKILL.md +123 -0
  116. package/skills/continuous-learning/config.json +18 -0
  117. package/skills/continuous-learning/evaluate-session.sh +69 -0
  118. package/skills/continuous-learning-v2/SKILL.md +365 -0
  119. package/skills/continuous-learning-v2/agents/observer-loop.sh +282 -0
  120. package/skills/continuous-learning-v2/agents/observer.md +198 -0
  121. package/skills/continuous-learning-v2/agents/session-guardian.sh +150 -0
  122. package/skills/continuous-learning-v2/agents/start-observer.sh +244 -0
  123. package/skills/continuous-learning-v2/config.json +8 -0
  124. package/skills/continuous-learning-v2/hooks/observe.sh +428 -0
  125. package/skills/continuous-learning-v2/scripts/detect-project.sh +228 -0
  126. package/skills/continuous-learning-v2/scripts/instinct-cli.py +1426 -0
  127. package/skills/continuous-learning-v2/scripts/test_parse_instinct.py +984 -0
  128. package/skills/cost-aware-llm-pipeline/SKILL.md +183 -0
  129. package/skills/council/SKILL.md +203 -0
  130. package/skills/cpp-coding-standards/SKILL.md +723 -0
  131. package/skills/cpp-testing/SKILL.md +324 -0
  132. package/skills/crosspost/SKILL.md +111 -0
  133. package/skills/csharp-testing/SKILL.md +321 -0
  134. package/skills/customer-billing-ops/SKILL.md +140 -0
  135. package/skills/customs-trade-compliance/SKILL.md +263 -0
  136. package/skills/dart-flutter-patterns/SKILL.md +563 -0
  137. package/skills/dashboard-builder/SKILL.md +108 -0
  138. package/skills/data-scraper-agent/SKILL.md +764 -0
  139. package/skills/database-migrations/SKILL.md +429 -0
  140. package/skills/deep-research/SKILL.md +155 -0
  141. package/skills/defi-amm-security/SKILL.md +160 -0
  142. package/skills/deployment-patterns/SKILL.md +427 -0
  143. package/skills/design-system/SKILL.md +82 -0
  144. package/skills/django-patterns/SKILL.md +734 -0
  145. package/skills/django-security/SKILL.md +593 -0
  146. package/skills/django-tdd/SKILL.md +729 -0
  147. package/skills/django-verification/SKILL.md +469 -0
  148. package/skills/dmux-workflows/SKILL.md +191 -0
  149. package/skills/docker-patterns/SKILL.md +364 -0
  150. package/skills/documentation-lookup/SKILL.md +90 -0
  151. package/skills/dotnet-patterns/SKILL.md +321 -0
  152. package/skills/e2e-testing/SKILL.md +326 -0
  153. package/skills/ecc-tools-cost-audit/SKILL.md +160 -0
  154. package/skills/email-ops/SKILL.md +121 -0
  155. package/skills/energy-procurement/SKILL.md +228 -0
  156. package/skills/enterprise-agent-ops/SKILL.md +50 -0
  157. package/skills/eval-harness/SKILL.md +270 -0
  158. package/skills/evm-token-decimals/SKILL.md +130 -0
  159. package/skills/exa-search/SKILL.md +103 -0
  160. package/skills/fal-ai-media/SKILL.md +284 -0
  161. package/skills/finance-billing-ops/SKILL.md +127 -0
  162. package/skills/flutter-dart-code-review/SKILL.md +435 -0
  163. package/skills/foundation-models-on-device/SKILL.md +243 -0
  164. package/skills/frontend-design/SKILL.md +145 -0
  165. package/skills/frontend-patterns/SKILL.md +642 -0
  166. package/skills/frontend-slides/SKILL.md +184 -0
  167. package/skills/frontend-slides/STYLE_PRESETS.md +330 -0
  168. package/skills/gan-style-harness/SKILL.md +278 -0
  169. package/skills/git-workflow/SKILL.md +715 -0
  170. package/skills/github-ops/SKILL.md +144 -0
  171. package/skills/golang-patterns/SKILL.md +674 -0
  172. package/skills/golang-testing/SKILL.md +720 -0
  173. package/skills/google-workspace-ops/SKILL.md +95 -0
  174. package/skills/healthcare-cdss-patterns/SKILL.md +245 -0
  175. package/skills/healthcare-emr-patterns/SKILL.md +159 -0
  176. package/skills/healthcare-eval-harness/SKILL.md +207 -0
  177. package/skills/healthcare-phi-compliance/SKILL.md +145 -0
  178. package/skills/hexagonal-architecture/SKILL.md +276 -0
  179. package/skills/hipaa-compliance/SKILL.md +78 -0
  180. package/skills/hookify-rules/SKILL.md +128 -0
  181. package/skills/inventory-demand-planning/SKILL.md +247 -0
  182. package/skills/investor-materials/SKILL.md +96 -0
  183. package/skills/investor-outreach/SKILL.md +91 -0
  184. package/skills/iterative-retrieval/SKILL.md +211 -0
  185. package/skills/java-coding-standards/SKILL.md +147 -0
  186. package/skills/jira-integration/SKILL.md +293 -0
  187. package/skills/jpa-patterns/SKILL.md +151 -0
  188. package/skills/knowledge-ops/SKILL.md +154 -0
  189. package/skills/kotlin-coroutines-flows/SKILL.md +284 -0
  190. package/skills/kotlin-exposed-patterns/SKILL.md +719 -0
  191. package/skills/kotlin-ktor-patterns/SKILL.md +689 -0
  192. package/skills/kotlin-patterns/SKILL.md +711 -0
  193. package/skills/kotlin-testing/SKILL.md +824 -0
  194. package/skills/laravel-patterns/SKILL.md +415 -0
  195. package/skills/laravel-plugin-discovery/SKILL.md +229 -0
  196. package/skills/laravel-security/SKILL.md +285 -0
  197. package/skills/laravel-tdd/SKILL.md +283 -0
  198. package/skills/laravel-verification/SKILL.md +179 -0
  199. package/skills/lead-intelligence/SKILL.md +321 -0
  200. package/skills/lead-intelligence/agents/enrichment-agent.md +85 -0
  201. package/skills/lead-intelligence/agents/mutual-mapper.md +75 -0
  202. package/skills/lead-intelligence/agents/outreach-drafter.md +98 -0
  203. package/skills/lead-intelligence/agents/signal-scorer.md +60 -0
  204. package/skills/liquid-glass-design/SKILL.md +279 -0
  205. package/skills/llm-trading-agent-security/SKILL.md +146 -0
  206. package/skills/logistics-exception-management/SKILL.md +222 -0
  207. package/skills/manim-video/SKILL.md +89 -0
  208. package/skills/manim-video/assets/network_graph_scene.py +52 -0
  209. package/skills/market-research/SKILL.md +75 -0
  210. package/skills/mcp-server-patterns/SKILL.md +69 -0
  211. package/skills/messages-ops/SKILL.md +104 -0
  212. package/skills/nanoclaw-repl/SKILL.md +33 -0
  213. package/skills/nestjs-patterns/SKILL.md +230 -0
  214. package/skills/nextjs-turbopack/SKILL.md +44 -0
  215. package/skills/nodejs-keccak256/SKILL.md +102 -0
  216. package/skills/nutrient-document-processing/SKILL.md +167 -0
  217. package/skills/nuxt4-patterns/SKILL.md +100 -0
  218. package/skills/openclaw-persona-forge/SKILL.md +296 -0
  219. package/skills/openclaw-persona-forge/gacha.py +224 -0
  220. package/skills/openclaw-persona-forge/gacha.sh +5 -0
  221. package/skills/openclaw-persona-forge/references/avatar-style.md +124 -0
  222. package/skills/openclaw-persona-forge/references/boundary-rules.md +53 -0
  223. package/skills/openclaw-persona-forge/references/error-handling.md +53 -0
  224. package/skills/openclaw-persona-forge/references/identity-tension.md +48 -0
  225. package/skills/openclaw-persona-forge/references/naming-system.md +39 -0
  226. package/skills/openclaw-persona-forge/references/output-template.md +166 -0
  227. package/skills/opensource-pipeline/SKILL.md +255 -0
  228. package/skills/pencil-design/SKILL.md +175 -0
  229. package/skills/perl-patterns/SKILL.md +504 -0
  230. package/skills/perl-security/SKILL.md +503 -0
  231. package/skills/perl-testing/SKILL.md +475 -0
  232. package/skills/plankton-code-quality/SKILL.md +236 -0
  233. package/skills/postgres-patterns/SKILL.md +147 -0
  234. package/skills/product-capability/SKILL.md +141 -0
  235. package/skills/product-lens/SKILL.md +92 -0
  236. package/skills/production-scheduling/SKILL.md +238 -0
  237. package/skills/project-flow-ops/SKILL.md +111 -0
  238. package/skills/prompt-optimizer/SKILL.md +397 -0
  239. package/skills/python-patterns/SKILL.md +750 -0
  240. package/skills/python-testing/SKILL.md +816 -0
  241. package/skills/pytorch-patterns/SKILL.md +396 -0
  242. package/skills/quality-nonconformance/SKILL.md +260 -0
  243. package/skills/ralphinho-rfc-pipeline/SKILL.md +67 -0
  244. package/skills/regex-vs-llm-structured-text/SKILL.md +220 -0
  245. package/skills/remotion-video-creation/SKILL.md +43 -0
  246. package/skills/remotion-video-creation/rules/3d.md +86 -0
  247. package/skills/remotion-video-creation/rules/animations.md +29 -0
  248. package/skills/remotion-video-creation/rules/assets/charts-bar-chart.tsx +173 -0
  249. package/skills/remotion-video-creation/rules/assets/text-animations-typewriter.tsx +100 -0
  250. package/skills/remotion-video-creation/rules/assets/text-animations-word-highlight.tsx +108 -0
  251. package/skills/remotion-video-creation/rules/assets.md +78 -0
  252. package/skills/remotion-video-creation/rules/audio.md +172 -0
  253. package/skills/remotion-video-creation/rules/calculate-metadata.md +104 -0
  254. package/skills/remotion-video-creation/rules/can-decode.md +75 -0
  255. package/skills/remotion-video-creation/rules/charts.md +58 -0
  256. package/skills/remotion-video-creation/rules/compositions.md +146 -0
  257. package/skills/remotion-video-creation/rules/display-captions.md +126 -0
  258. package/skills/remotion-video-creation/rules/extract-frames.md +229 -0
  259. package/skills/remotion-video-creation/rules/fonts.md +152 -0
  260. package/skills/remotion-video-creation/rules/get-audio-duration.md +58 -0
  261. package/skills/remotion-video-creation/rules/get-video-dimensions.md +68 -0
  262. package/skills/remotion-video-creation/rules/get-video-duration.md +58 -0
  263. package/skills/remotion-video-creation/rules/gifs.md +138 -0
  264. package/skills/remotion-video-creation/rules/images.md +130 -0
  265. package/skills/remotion-video-creation/rules/import-srt-captions.md +67 -0
  266. package/skills/remotion-video-creation/rules/lottie.md +67 -0
  267. package/skills/remotion-video-creation/rules/measuring-dom-nodes.md +34 -0
  268. package/skills/remotion-video-creation/rules/measuring-text.md +143 -0
  269. package/skills/remotion-video-creation/rules/sequencing.md +106 -0
  270. package/skills/remotion-video-creation/rules/tailwind.md +11 -0
  271. package/skills/remotion-video-creation/rules/text-animations.md +20 -0
  272. package/skills/remotion-video-creation/rules/timing.md +179 -0
  273. package/skills/remotion-video-creation/rules/transcribe-captions.md +19 -0
  274. package/skills/remotion-video-creation/rules/transitions.md +122 -0
  275. package/skills/remotion-video-creation/rules/trimming.md +52 -0
  276. package/skills/remotion-video-creation/rules/videos.md +171 -0
  277. package/skills/repo-scan/SKILL.md +78 -0
  278. package/skills/research-ops/SKILL.md +112 -0
  279. package/skills/returns-reverse-logistics/SKILL.md +240 -0
  280. package/skills/rules-distill/SKILL.md +264 -0
  281. package/skills/rules-distill/scripts/scan-rules.sh +58 -0
  282. package/skills/rules-distill/scripts/scan-skills.sh +129 -0
  283. package/skills/rust-patterns/SKILL.md +499 -0
  284. package/skills/rust-testing/SKILL.md +500 -0
  285. package/skills/safety-guard/SKILL.md +75 -0
  286. package/skills/santa-method/SKILL.md +306 -0
  287. package/skills/search-first/SKILL.md +161 -0
  288. package/skills/security-bounty-hunter/SKILL.md +99 -0
  289. package/skills/security-review/SKILL.md +495 -0
  290. package/skills/security-review/cloud-infrastructure-security.md +361 -0
  291. package/skills/security-scan/SKILL.md +165 -0
  292. package/skills/seo/SKILL.md +154 -0
  293. package/skills/skill-comply/SKILL.md +58 -0
  294. package/skills/skill-comply/fixtures/compliant_trace.jsonl +5 -0
  295. package/skills/skill-comply/fixtures/noncompliant_trace.jsonl +3 -0
  296. package/skills/skill-comply/fixtures/tdd_spec.yaml +44 -0
  297. package/skills/skill-comply/prompts/classifier.md +24 -0
  298. package/skills/skill-comply/prompts/scenario_generator.md +62 -0
  299. package/skills/skill-comply/prompts/spec_generator.md +42 -0
  300. package/skills/skill-comply/pyproject.toml +15 -0
  301. package/skills/skill-comply/scripts/__init__.py +0 -0
  302. package/skills/skill-comply/scripts/classifier.py +85 -0
  303. package/skills/skill-comply/scripts/grader.py +122 -0
  304. package/skills/skill-comply/scripts/parser.py +107 -0
  305. package/skills/skill-comply/scripts/report.py +170 -0
  306. package/skills/skill-comply/scripts/run.py +127 -0
  307. package/skills/skill-comply/scripts/runner.py +161 -0
  308. package/skills/skill-comply/scripts/scenario_generator.py +70 -0
  309. package/skills/skill-comply/scripts/spec_generator.py +72 -0
  310. package/skills/skill-comply/scripts/utils.py +13 -0
  311. package/skills/skill-comply/tests/test_grader.py +137 -0
  312. package/skills/skill-comply/tests/test_parser.py +90 -0
  313. package/skills/skill-stocktake/SKILL.md +193 -0
  314. package/skills/skill-stocktake/scripts/quick-diff.sh +87 -0
  315. package/skills/skill-stocktake/scripts/save-results.sh +56 -0
  316. package/skills/skill-stocktake/scripts/scan.sh +170 -0
  317. package/skills/social-graph-ranker/SKILL.md +154 -0
  318. package/skills/springboot-patterns/SKILL.md +314 -0
  319. package/skills/springboot-security/SKILL.md +272 -0
  320. package/skills/springboot-tdd/SKILL.md +158 -0
  321. package/skills/springboot-verification/SKILL.md +231 -0
  322. package/skills/strategic-compact/SKILL.md +131 -0
  323. package/skills/strategic-compact/suggest-compact.sh +54 -0
  324. package/skills/swift-actor-persistence/SKILL.md +143 -0
  325. package/skills/swift-concurrency-6-2/SKILL.md +216 -0
  326. package/skills/swift-protocol-di-testing/SKILL.md +190 -0
  327. package/skills/swiftui-patterns/SKILL.md +259 -0
  328. package/skills/tdd-workflow/SKILL.md +463 -0
  329. package/skills/team-builder/SKILL.md +168 -0
  330. package/skills/terminal-ops/SKILL.md +109 -0
  331. package/skills/token-budget-advisor/SKILL.md +133 -0
  332. package/skills/ui-demo/SKILL.md +465 -0
  333. package/skills/unified-notifications-ops/SKILL.md +187 -0
  334. package/skills/verification-loop/SKILL.md +126 -0
  335. package/skills/video-editing/SKILL.md +310 -0
  336. package/skills/videodb/SKILL.md +374 -0
  337. package/skills/videodb/reference/api-reference.md +550 -0
  338. package/skills/videodb/reference/capture-reference.md +407 -0
  339. package/skills/videodb/reference/capture.md +101 -0
  340. package/skills/videodb/reference/editor.md +443 -0
  341. package/skills/videodb/reference/generative.md +331 -0
  342. package/skills/videodb/reference/rtstream-reference.md +564 -0
  343. package/skills/videodb/reference/rtstream.md +65 -0
  344. package/skills/videodb/reference/search.md +230 -0
  345. package/skills/videodb/reference/streaming.md +406 -0
  346. package/skills/videodb/reference/use-cases.md +118 -0
  347. package/skills/videodb/scripts/ws_listener.py +282 -0
  348. package/skills/visa-doc-translate/README.md +86 -0
  349. package/skills/visa-doc-translate/SKILL.md +117 -0
  350. package/skills/workspace-surface-audit/SKILL.md +125 -0
  351. package/skills/x-api/SKILL.md +230 -0
  352. package/tools/changed-files.ts +83 -0
  353. package/tools/check-coverage.ts +172 -0
  354. package/tools/format-code.ts +70 -0
  355. package/tools/git-summary.ts +56 -0
  356. package/tools/index.ts +14 -0
  357. package/tools/lint-check.ts +87 -0
  358. package/tools/run-tests.ts +141 -0
  359. package/tools/security-audit.ts +279 -0
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: workspace-surface-audit
3
+ description: Audit the active repo, MCP servers, plugins, connectors, env surfaces, and harness setup, then recommend the highest-value ECC-native skills, hooks, agents, and operator workflows. Use when the user wants help setting up Claude Code or understanding what capabilities are actually available in their environment.
4
+ origin: ECC
5
+ ---
6
+
7
+ # Workspace Surface Audit
8
+
9
+ Read-only audit skill for answering the question "what can this workspace and machine actually do right now, and what should we add or enable next?"
10
+
11
+ This is the ECC-native answer to setup-audit plugins. It does not modify files unless the user explicitly asks for follow-up implementation.
12
+
13
+ ## When to Use
14
+
15
+ - User says "set up Claude Code", "recommend automations", "what plugins or MCPs should I use?", or "what am I missing?"
16
+ - Auditing a machine or repo before installing more skills, hooks, or connectors
17
+ - Comparing official marketplace plugins against ECC-native coverage
18
+ - Reviewing `.env`, `.mcp.json`, plugin settings, or connected-app surfaces to find missing workflow layers
19
+ - Deciding whether a capability should be a skill, hook, agent, MCP, or external connector
20
+
21
+ ## Non-Negotiable Rules
22
+
23
+ - Never print secret values. Surface only provider names, capability names, file paths, and whether a key or config exists.
24
+ - Prefer ECC-native workflows over generic "install another plugin" advice when ECC can reasonably own the surface.
25
+ - Treat external plugins as benchmarks and inspiration, not authoritative product boundaries.
26
+ - Separate three things clearly:
27
+ - already available now
28
+ - available but not wrapped well in ECC
29
+ - not available and would require a new integration
30
+
31
+ ## Audit Inputs
32
+
33
+ Inspect only the files and settings needed to answer the question well:
34
+
35
+ 1. Repo surface
36
+ - `package.json`, lockfiles, language markers, framework config, `README.md`
37
+ - `.mcp.json`, `.lsp.json`, `.claude/settings*.json`, `.codex/*`
38
+ - `AGENTS.md`, `CLAUDE.md`, install manifests, hook configs
39
+ 2. Environment surface
40
+ - `.env*` files in the active repo and obvious adjacent ECC workspaces
41
+ - Surface only key names such as `STRIPE_API_KEY`, `TWILIO_AUTH_TOKEN`, `FAL_KEY`
42
+ 3. Connected tool surface
43
+ - Installed plugins, enabled connectors, MCP servers, LSPs, and app integrations
44
+ 4. ECC surface
45
+ - Existing skills, commands, hooks, agents, and install modules that already cover the need
46
+
47
+ ## Audit Process
48
+
49
+ ### Phase 1: Inventory What Exists
50
+
51
+ Produce a compact inventory:
52
+
53
+ - active harness targets
54
+ - installed plugins and connected apps
55
+ - configured MCP servers
56
+ - configured LSP servers
57
+ - env-backed services implied by key names
58
+ - existing ECC skills already relevant to the workspace
59
+
60
+ If a surface exists only as a primitive, call that out. Example:
61
+
62
+ - "Stripe is available via connected app, but ECC lacks a billing-operator skill"
63
+ - "Google Drive is connected, but there is no ECC-native Google Workspace operator workflow"
64
+
65
+ ### Phase 2: Benchmark Against Official and Installed Surfaces
66
+
67
+ Compare the workspace against:
68
+
69
+ - official Claude plugins that overlap with setup, review, docs, design, or workflow quality
70
+ - locally installed plugins in Claude or Codex
71
+ - the user's currently connected app surfaces
72
+
73
+ Do not just list names. For each comparison, answer:
74
+
75
+ 1. what they actually do
76
+ 2. whether ECC already has parity
77
+ 3. whether ECC only has primitives
78
+ 4. whether ECC is missing the workflow entirely
79
+
80
+ ### Phase 3: Turn Gaps Into ECC Decisions
81
+
82
+ For every real gap, recommend the correct ECC-native shape:
83
+
84
+ | Gap Type | Preferred ECC Shape |
85
+ |----------|---------------------|
86
+ | Repeatable operator workflow | Skill |
87
+ | Automatic enforcement or side-effect | Hook |
88
+ | Specialized delegated role | Agent |
89
+ | External tool bridge | MCP server or connector |
90
+ | Install/bootstrap guidance | Setup or audit skill |
91
+
92
+ Default to user-facing skills that orchestrate existing tools when the need is operational rather than infrastructural.
93
+
94
+ ## Output Format
95
+
96
+ Return five sections in this order:
97
+
98
+ 1. **Current surface**
99
+ - what is already usable right now
100
+ 2. **Parity**
101
+ - where ECC already matches or exceeds the benchmark
102
+ 3. **Primitive-only gaps**
103
+ - tools exist, but ECC lacks a clean operator skill
104
+ 4. **Missing integrations**
105
+ - capability not available yet
106
+ 5. **Top 3-5 next moves**
107
+ - concrete ECC-native additions, ordered by impact
108
+
109
+ ## Recommendation Rules
110
+
111
+ - Recommend at most 1-2 highest-value ideas per category.
112
+ - Favor skills with obvious user intent and business value:
113
+ - setup audit
114
+ - billing/customer ops
115
+ - issue/program ops
116
+ - Google Workspace ops
117
+ - deployment/ops control
118
+ - If a connector is company-specific, recommend it only when it is genuinely available or clearly useful to the user's workflow.
119
+ - If ECC already has a strong primitive, propose a wrapper skill instead of inventing a brand-new subsystem.
120
+
121
+ ## Good Outcomes
122
+
123
+ - The user can immediately see what is connected, what is missing, and what ECC should own next.
124
+ - Recommendations are specific enough to implement in the repo without another discovery pass.
125
+ - The final answer is organized around workflows, not API brands.
@@ -0,0 +1,230 @@
1
+ ---
2
+ name: x-api
3
+ description: X/Twitter API integration for posting tweets, threads, reading timelines, search, and analytics. Covers OAuth auth patterns, rate limits, and platform-native content posting. Use when the user wants to interact with X programmatically.
4
+ origin: ECC
5
+ ---
6
+
7
+ # X API
8
+
9
+ Programmatic interaction with X (Twitter) for posting, reading, searching, and analytics.
10
+
11
+ ## When to Activate
12
+
13
+ - User wants to post tweets or threads programmatically
14
+ - Reading timeline, mentions, or user data from X
15
+ - Searching X for content, trends, or conversations
16
+ - Building X integrations or bots
17
+ - Analytics and engagement tracking
18
+ - User says "post to X", "tweet", "X API", or "Twitter API"
19
+
20
+ ## Authentication
21
+
22
+ ### OAuth 2.0 Bearer Token (App-Only)
23
+
24
+ Best for: read-heavy operations, search, public data.
25
+
26
+ ```bash
27
+ # Environment setup
28
+ export X_BEARER_TOKEN="your-bearer-token"
29
+ ```
30
+
31
+ ```python
32
+ import os
33
+ import requests
34
+
35
+ bearer = os.environ["X_BEARER_TOKEN"]
36
+ headers = {"Authorization": f"Bearer {bearer}"}
37
+
38
+ # Search recent tweets
39
+ resp = requests.get(
40
+ "https://api.x.com/2/tweets/search/recent",
41
+ headers=headers,
42
+ params={"query": "claude code", "max_results": 10}
43
+ )
44
+ tweets = resp.json()
45
+ ```
46
+
47
+ ### OAuth 1.0a (User Context)
48
+
49
+ Required for: posting tweets, managing account, DMs, and any write flow.
50
+
51
+ ```bash
52
+ # Environment setup — source before use
53
+ export X_CONSUMER_KEY="your-consumer-key"
54
+ export X_CONSUMER_SECRET="your-consumer-secret"
55
+ export X_ACCESS_TOKEN="your-access-token"
56
+ export X_ACCESS_TOKEN_SECRET="your-access-token-secret"
57
+ ```
58
+
59
+ Legacy aliases such as `X_API_KEY`, `X_API_SECRET`, and `X_ACCESS_SECRET` may exist in older setups. Prefer the `X_CONSUMER_*` and `X_ACCESS_TOKEN_SECRET` names when documenting or wiring new flows.
60
+
61
+ ```python
62
+ import os
63
+ from requests_oauthlib import OAuth1Session
64
+
65
+ oauth = OAuth1Session(
66
+ os.environ["X_CONSUMER_KEY"],
67
+ client_secret=os.environ["X_CONSUMER_SECRET"],
68
+ resource_owner_key=os.environ["X_ACCESS_TOKEN"],
69
+ resource_owner_secret=os.environ["X_ACCESS_TOKEN_SECRET"],
70
+ )
71
+ ```
72
+
73
+ ## Core Operations
74
+
75
+ ### Post a Tweet
76
+
77
+ ```python
78
+ resp = oauth.post(
79
+ "https://api.x.com/2/tweets",
80
+ json={"text": "Hello from Claude Code"}
81
+ )
82
+ resp.raise_for_status()
83
+ tweet_id = resp.json()["data"]["id"]
84
+ ```
85
+
86
+ ### Post a Thread
87
+
88
+ ```python
89
+ def post_thread(oauth, tweets: list[str]) -> list[str]:
90
+ ids = []
91
+ reply_to = None
92
+ for text in tweets:
93
+ payload = {"text": text}
94
+ if reply_to:
95
+ payload["reply"] = {"in_reply_to_tweet_id": reply_to}
96
+ resp = oauth.post("https://api.x.com/2/tweets", json=payload)
97
+ tweet_id = resp.json()["data"]["id"]
98
+ ids.append(tweet_id)
99
+ reply_to = tweet_id
100
+ return ids
101
+ ```
102
+
103
+ ### Read User Timeline
104
+
105
+ ```python
106
+ resp = requests.get(
107
+ f"https://api.x.com/2/users/{user_id}/tweets",
108
+ headers=headers,
109
+ params={
110
+ "max_results": 10,
111
+ "tweet.fields": "created_at,public_metrics",
112
+ }
113
+ )
114
+ ```
115
+
116
+ ### Search Tweets
117
+
118
+ ```python
119
+ resp = requests.get(
120
+ "https://api.x.com/2/tweets/search/recent",
121
+ headers=headers,
122
+ params={
123
+ "query": "from:affaanmustafa -is:retweet",
124
+ "max_results": 10,
125
+ "tweet.fields": "public_metrics,created_at",
126
+ }
127
+ )
128
+ ```
129
+
130
+ ### Pull Recent Original Posts for Voice Modeling
131
+
132
+ ```python
133
+ resp = requests.get(
134
+ "https://api.x.com/2/tweets/search/recent",
135
+ headers=headers,
136
+ params={
137
+ "query": "from:affaanmustafa -is:retweet -is:reply",
138
+ "max_results": 25,
139
+ "tweet.fields": "created_at,public_metrics",
140
+ }
141
+ )
142
+ voice_samples = resp.json()
143
+ ```
144
+
145
+ ### Get User by Username
146
+
147
+ ```python
148
+ resp = requests.get(
149
+ "https://api.x.com/2/users/by/username/affaanmustafa",
150
+ headers=headers,
151
+ params={"user.fields": "public_metrics,description,created_at"}
152
+ )
153
+ ```
154
+
155
+ ### Upload Media and Post
156
+
157
+ ```python
158
+ # Media upload uses v1.1 endpoint
159
+
160
+ # Step 1: Upload media
161
+ media_resp = oauth.post(
162
+ "https://upload.twitter.com/1.1/media/upload.json",
163
+ files={"media": open("image.png", "rb")}
164
+ )
165
+ media_id = media_resp.json()["media_id_string"]
166
+
167
+ # Step 2: Post with media
168
+ resp = oauth.post(
169
+ "https://api.x.com/2/tweets",
170
+ json={"text": "Check this out", "media": {"media_ids": [media_id]}}
171
+ )
172
+ ```
173
+
174
+ ## Rate Limits
175
+
176
+ X API rate limits vary by endpoint, auth method, and account tier, and they change over time. Always:
177
+ - Check the current X developer docs before hardcoding assumptions
178
+ - Read `x-rate-limit-remaining` and `x-rate-limit-reset` headers at runtime
179
+ - Back off automatically instead of relying on static tables in code
180
+
181
+ ```python
182
+ import time
183
+
184
+ remaining = int(resp.headers.get("x-rate-limit-remaining", 0))
185
+ if remaining < 5:
186
+ reset = int(resp.headers.get("x-rate-limit-reset", 0))
187
+ wait = max(0, reset - int(time.time()))
188
+ print(f"Rate limit approaching. Resets in {wait}s")
189
+ ```
190
+
191
+ ## Error Handling
192
+
193
+ ```python
194
+ resp = oauth.post("https://api.x.com/2/tweets", json={"text": content})
195
+ if resp.status_code == 201:
196
+ return resp.json()["data"]["id"]
197
+ elif resp.status_code == 429:
198
+ reset = int(resp.headers["x-rate-limit-reset"])
199
+ raise Exception(f"Rate limited. Resets at {reset}")
200
+ elif resp.status_code == 403:
201
+ raise Exception(f"Forbidden: {resp.json().get('detail', 'check permissions')}")
202
+ else:
203
+ raise Exception(f"X API error {resp.status_code}: {resp.text}")
204
+ ```
205
+
206
+ ## Security
207
+
208
+ - **Never hardcode tokens.** Use environment variables or `.env` files.
209
+ - **Never commit `.env` files.** Add to `.gitignore`.
210
+ - **Rotate tokens** if exposed. Regenerate at developer.x.com.
211
+ - **Use read-only tokens** when write access is not needed.
212
+ - **Store OAuth secrets securely** — not in source code or logs.
213
+
214
+ ## Integration with Content Engine
215
+
216
+ Use `brand-voice` plus `content-engine` to generate platform-native content, then post via X API:
217
+ 1. Pull recent original posts when voice matching matters
218
+ 2. Build or reuse a `VOICE PROFILE`
219
+ 3. Generate content with `content-engine` in X-native format
220
+ 4. Validate length and thread structure
221
+ 5. Return the draft for approval unless the user explicitly asked to post now
222
+ 6. Post via X API only after approval
223
+ 7. Track engagement via public_metrics
224
+
225
+ ## Related Skills
226
+
227
+ - `brand-voice` — Build a reusable voice profile from real X and site/source material
228
+ - `content-engine` — Generate platform-native content for X
229
+ - `crosspost` — Distribute content across X, LinkedIn, and other platforms
230
+ - `connections-optimizer` — Reorganize the X graph before drafting network-driven outreach
@@ -0,0 +1,83 @@
1
+ import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
2
+ import {
3
+ buildTree,
4
+ getChangedPaths,
5
+ hasChanges,
6
+ type ChangeType,
7
+ type TreeNode,
8
+ } from "../plugins/lib/changed-files-store.js"
9
+
10
+ const INDICATORS: Record<ChangeType, string> = {
11
+ added: "+",
12
+ modified: "~",
13
+ deleted: "-",
14
+ }
15
+
16
+ function renderTree(nodes: TreeNode[], indent: string): string {
17
+ const lines: string[] = []
18
+ for (const node of nodes) {
19
+ const indicator = node.changeType ? ` (${INDICATORS[node.changeType]})` : ""
20
+ const name = node.changeType ? `${node.name}${indicator}` : `${node.name}/`
21
+ lines.push(`${indent}${name}`)
22
+ if (node.children.length > 0) {
23
+ lines.push(renderTree(node.children, `${indent} `))
24
+ }
25
+ }
26
+ return lines.join("\n")
27
+ }
28
+
29
+ const changedFilesTool: ToolDefinition = tool({
30
+ description:
31
+ "List files changed by agents in this session as a navigable tree. Shows added (+), modified (~), and deleted (-) indicators. Use filter to show only specific change types. Returns paths for git diff.",
32
+ args: {
33
+ filter: tool.schema
34
+ .enum(["all", "added", "modified", "deleted"])
35
+ .optional()
36
+ .describe("Filter by change type (default: all)"),
37
+ format: tool.schema
38
+ .enum(["tree", "json"])
39
+ .optional()
40
+ .describe("Output format: tree for terminal display, json for structured data (default: tree)"),
41
+ },
42
+ async execute(args, context) {
43
+ const filter = args.filter === "all" || !args.filter ? undefined : (args.filter as ChangeType)
44
+ const format = args.format ?? "tree"
45
+
46
+ if (!hasChanges()) {
47
+ return JSON.stringify({ changed: false, message: "No files changed in this session" })
48
+ }
49
+
50
+ const paths = getChangedPaths(filter)
51
+
52
+ if (format === "json") {
53
+ return JSON.stringify(
54
+ {
55
+ changed: true,
56
+ filter: filter ?? "all",
57
+ files: paths.map((p) => ({ path: p.path, changeType: p.changeType })),
58
+ diffCommands: paths
59
+ .filter((p) => p.changeType !== "added")
60
+ .map((p) => `git diff ${p.path}`),
61
+ },
62
+ null,
63
+ 2
64
+ )
65
+ }
66
+
67
+ const tree = buildTree(filter)
68
+ const treeStr = renderTree(tree, "")
69
+ const diffHint = paths
70
+ .filter((p) => p.changeType !== "added")
71
+ .slice(0, 5)
72
+ .map((p) => ` git diff ${p.path}`)
73
+ .join("\n")
74
+
75
+ let output = `Changed files (${paths.length}):\n\n${treeStr}`
76
+ if (diffHint) {
77
+ output += `\n\nTo view diff for a file:\n${diffHint}`
78
+ }
79
+ return output
80
+ },
81
+ })
82
+
83
+ export default changedFilesTool
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Check Coverage Tool
3
+ *
4
+ * Custom OpenCode tool to analyze test coverage and report on gaps.
5
+ * Supports common coverage report formats.
6
+ */
7
+
8
+ import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
9
+ import * as path from "path"
10
+ import * as fs from "fs"
11
+
12
+ const checkCoverageTool: ToolDefinition = tool({
13
+ description:
14
+ "Check test coverage against a threshold and identify files with low coverage. Reads coverage reports from common locations.",
15
+ args: {
16
+ threshold: tool.schema
17
+ .number()
18
+ .optional()
19
+ .describe("Minimum coverage percentage required (default: 80)"),
20
+ showUncovered: tool.schema
21
+ .boolean()
22
+ .optional()
23
+ .describe("Show list of uncovered files (default: true)"),
24
+ format: tool.schema
25
+ .enum(["summary", "detailed", "json"])
26
+ .optional()
27
+ .describe("Output format (default: summary)"),
28
+ },
29
+ async execute(args, context) {
30
+ const threshold = args.threshold ?? 80
31
+ const showUncovered = args.showUncovered ?? true
32
+ const format = args.format ?? "summary"
33
+ const cwd = context.worktree || context.directory
34
+
35
+ // Look for coverage reports
36
+ const coveragePaths = [
37
+ "coverage/coverage-summary.json",
38
+ "coverage/lcov-report/index.html",
39
+ "coverage/coverage-final.json",
40
+ ".nyc_output/coverage.json",
41
+ ]
42
+
43
+ let coverageData: CoverageSummary | null = null
44
+ let coverageFile: string | null = null
45
+
46
+ for (const coveragePath of coveragePaths) {
47
+ const fullPath = path.join(cwd, coveragePath)
48
+ if (fs.existsSync(fullPath) && coveragePath.endsWith(".json")) {
49
+ try {
50
+ const content = JSON.parse(fs.readFileSync(fullPath, "utf-8"))
51
+ coverageData = parseCoverageData(content)
52
+ coverageFile = coveragePath
53
+ break
54
+ } catch {
55
+ // Continue to next file
56
+ }
57
+ }
58
+ }
59
+
60
+ if (!coverageData) {
61
+ return JSON.stringify({
62
+ success: false,
63
+ error: "No coverage report found",
64
+ suggestion:
65
+ "Run tests with coverage first: npm test -- --coverage",
66
+ searchedPaths: coveragePaths,
67
+ })
68
+ }
69
+
70
+ const passed = coverageData.total.percentage >= threshold
71
+ const uncoveredFiles = coverageData.files.filter(
72
+ (f) => f.percentage < threshold
73
+ )
74
+
75
+ const result: CoverageResult = {
76
+ success: passed,
77
+ threshold,
78
+ coverageFile,
79
+ total: coverageData.total,
80
+ passed,
81
+ }
82
+
83
+ if (format === "detailed" || (showUncovered && uncoveredFiles.length > 0)) {
84
+ result.uncoveredFiles = uncoveredFiles.slice(0, 20) // Limit to 20 files
85
+ result.uncoveredCount = uncoveredFiles.length
86
+ }
87
+
88
+ if (format === "json") {
89
+ result.rawData = coverageData
90
+ }
91
+
92
+ if (!passed) {
93
+ result.suggestion = `Coverage is ${coverageData.total.percentage.toFixed(1)}% which is below the ${threshold}% threshold. Focus on these files:\n${uncoveredFiles
94
+ .slice(0, 5)
95
+ .map((f) => `- ${f.file}: ${f.percentage.toFixed(1)}%`)
96
+ .join("\n")}`
97
+ }
98
+
99
+ return JSON.stringify(result)
100
+ },
101
+ })
102
+
103
+ export default checkCoverageTool
104
+
105
+ interface CoverageSummary {
106
+ total: {
107
+ lines: number
108
+ covered: number
109
+ percentage: number
110
+ }
111
+ files: Array<{
112
+ file: string
113
+ lines: number
114
+ covered: number
115
+ percentage: number
116
+ }>
117
+ }
118
+
119
+ interface CoverageResult {
120
+ success: boolean
121
+ threshold: number
122
+ coverageFile: string | null
123
+ total: CoverageSummary["total"]
124
+ passed: boolean
125
+ uncoveredFiles?: CoverageSummary["files"]
126
+ uncoveredCount?: number
127
+ rawData?: CoverageSummary
128
+ suggestion?: string
129
+ }
130
+
131
+ function parseCoverageData(data: unknown): CoverageSummary {
132
+ // Handle istanbul/nyc format
133
+ if (typeof data === "object" && data !== null && "total" in data) {
134
+ const istanbulData = data as Record<string, unknown>
135
+ const total = istanbulData.total as Record<string, { total: number; covered: number }>
136
+
137
+ const files: CoverageSummary["files"] = []
138
+
139
+ for (const [key, value] of Object.entries(istanbulData)) {
140
+ if (key !== "total" && typeof value === "object" && value !== null) {
141
+ const fileData = value as Record<string, { total: number; covered: number }>
142
+ if (fileData.lines) {
143
+ files.push({
144
+ file: key,
145
+ lines: fileData.lines.total,
146
+ covered: fileData.lines.covered,
147
+ percentage: fileData.lines.total > 0
148
+ ? (fileData.lines.covered / fileData.lines.total) * 100
149
+ : 100,
150
+ })
151
+ }
152
+ }
153
+ }
154
+
155
+ return {
156
+ total: {
157
+ lines: total.lines?.total || 0,
158
+ covered: total.lines?.covered || 0,
159
+ percentage: total.lines?.total
160
+ ? (total.lines.covered / total.lines.total) * 100
161
+ : 0,
162
+ },
163
+ files,
164
+ }
165
+ }
166
+
167
+ // Default empty result
168
+ return {
169
+ total: { lines: 0, covered: 0, percentage: 0 },
170
+ files: [],
171
+ }
172
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * ECC Custom Tool: Format Code
3
+ *
4
+ * Returns the formatter command that should be run for a given file.
5
+ * This avoids shell execution assumptions while still giving precise guidance.
6
+ */
7
+
8
+ import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
9
+ import * as path from "path"
10
+ import * as fs from "fs"
11
+
12
+ type Formatter = "biome" | "prettier" | "black" | "gofmt" | "rustfmt"
13
+
14
+ const formatCodeTool: ToolDefinition = tool({
15
+ description:
16
+ "Detect formatter for a file and return the exact command to run (Biome, Prettier, Black, gofmt, rustfmt).",
17
+ args: {
18
+ filePath: tool.schema.string().describe("Path to the file to format"),
19
+ formatter: tool.schema
20
+ .enum(["biome", "prettier", "black", "gofmt", "rustfmt"])
21
+ .optional()
22
+ .describe("Optional formatter override"),
23
+ },
24
+ async execute(args, context) {
25
+ const cwd = context.worktree || context.directory
26
+ const ext = args.filePath.split(".").pop()?.toLowerCase() || ""
27
+ const detected = args.formatter || detectFormatter(cwd, ext)
28
+
29
+ if (!detected) {
30
+ return JSON.stringify({
31
+ success: false,
32
+ message: `No formatter detected for .${ext} files`,
33
+ })
34
+ }
35
+
36
+ const command = buildFormatterCommand(detected, args.filePath)
37
+ return JSON.stringify({
38
+ success: true,
39
+ formatter: detected,
40
+ command,
41
+ instructions: `Run this command:\n\n${command}`,
42
+ })
43
+ },
44
+ })
45
+
46
+ export default formatCodeTool
47
+
48
+ function detectFormatter(cwd: string, ext: string): Formatter | null {
49
+ if (["ts", "tsx", "js", "jsx", "json", "css", "scss", "md", "yaml", "yml"].includes(ext)) {
50
+ if (fs.existsSync(path.join(cwd, "biome.json")) || fs.existsSync(path.join(cwd, "biome.jsonc"))) {
51
+ return "biome"
52
+ }
53
+ return "prettier"
54
+ }
55
+ if (["py", "pyi"].includes(ext)) return "black"
56
+ if (ext === "go") return "gofmt"
57
+ if (ext === "rs") return "rustfmt"
58
+ return null
59
+ }
60
+
61
+ function buildFormatterCommand(formatter: Formatter, filePath: string): string {
62
+ const commands: Record<Formatter, string> = {
63
+ biome: `npx @biomejs/biome format --write ${filePath}`,
64
+ prettier: `npx prettier --write ${filePath}`,
65
+ black: `black ${filePath}`,
66
+ gofmt: `gofmt -w ${filePath}`,
67
+ rustfmt: `rustfmt ${filePath}`,
68
+ }
69
+ return commands[formatter]
70
+ }