@openhands/extensions 0.1.0 → 0.2.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 (347) hide show
  1. package/.agents/skills/custom-codereview-guide.md +25 -0
  2. package/.github/pull_request_template.md +38 -0
  3. package/.github/release.yml +14 -0
  4. package/.github/workflows/check-extensions.yml +72 -0
  5. package/.github/workflows/npm-publish.yml +89 -0
  6. package/.github/workflows/pr.yml +30 -0
  7. package/.github/workflows/release.yml +24 -0
  8. package/.github/workflows/tests.yml +25 -0
  9. package/.github/workflows/vulnerability-scan.yml +87 -0
  10. package/.release-please-manifest.json +3 -0
  11. package/AGENTS.md +132 -0
  12. package/README.md +10 -0
  13. package/analysis_results.md +162 -0
  14. package/marketplaces/large-codebase.json +66 -0
  15. package/marketplaces/openhands-extensions.json +682 -0
  16. package/package.json +4 -10
  17. package/plugins/README.md +30 -0
  18. package/plugins/city-weather/.plugin/plugin.json +13 -0
  19. package/plugins/city-weather/README.md +145 -0
  20. package/plugins/city-weather/commands/now.md +56 -0
  21. package/plugins/cobol-modernization/.plugin/plugin.json +19 -0
  22. package/plugins/cobol-modernization/README.md +201 -0
  23. package/plugins/cobol-modernization/references/troubleshooting.md +18 -0
  24. package/plugins/cobol-modernization/skills/build-setup/SKILL.md +78 -0
  25. package/plugins/cobol-modernization/skills/build-setup/scripts/install-gnucobol.sh +32 -0
  26. package/plugins/cobol-modernization/skills/cobol-modernization-overview/SKILL.md +113 -0
  27. package/plugins/cobol-modernization/skills/mainfraime-removal/SKILL.md +62 -0
  28. package/plugins/cobol-modernization/skills/mainfraime-removal/references/cics-transformation-examples.md +45 -0
  29. package/plugins/cobol-modernization/skills/mainframe-planning/SKILL.md +78 -0
  30. package/plugins/cobol-modernization/skills/to-java-migration/SKILL.md +59 -0
  31. package/plugins/cobol-modernization/skills/to-java-migration/references/cobol-to-java-example.md +58 -0
  32. package/plugins/cobol-modernization/skills/to-java-migration/references/datatype-mappings.md +19 -0
  33. package/plugins/issue-duplicate-checker/.plugin/plugin.json +13 -0
  34. package/plugins/issue-duplicate-checker/README.md +51 -0
  35. package/plugins/issue-duplicate-checker/action.yml +349 -0
  36. package/plugins/issue-duplicate-checker/scripts/auto_close_duplicate_issues.py +569 -0
  37. package/plugins/issue-duplicate-checker/scripts/issue_duplicate_check_openhands.py +681 -0
  38. package/plugins/issue-duplicate-checker/scripts/post_duplicate_notice.js +220 -0
  39. package/plugins/issue-duplicate-checker/scripts/remove_duplicate_candidate_label.js +27 -0
  40. package/plugins/magic-test/.plugin/plugin.json +13 -0
  41. package/plugins/magic-test/skills/magic-word/SKILL.md +33 -0
  42. package/plugins/migration-scoring/.plugin/plugin.json +19 -0
  43. package/plugins/migration-scoring/README.md +244 -0
  44. package/plugins/migration-scoring/skills/migration-mapping/SKILL.md +72 -0
  45. package/plugins/migration-scoring/skills/migration-report/SKILL.md +118 -0
  46. package/plugins/migration-scoring/skills/migration-scoring-overview/SKILL.md +126 -0
  47. package/plugins/migration-scoring/skills/score-quality/SKILL.md +54 -0
  48. package/plugins/migration-scoring/skills/score-quality/references/scoring-criteria.md +30 -0
  49. package/plugins/migration-scoring/skills/score-style/SKILL.md +106 -0
  50. package/plugins/onboarding/.plugin/plugin.json +20 -0
  51. package/plugins/onboarding/README.md +30 -0
  52. package/plugins/onboarding/references/criteria.md +144 -0
  53. package/plugins/onboarding/skills/agent-readiness-report/README.md +23 -0
  54. package/plugins/onboarding/skills/agent-readiness-report/SKILL.md +122 -0
  55. package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_agent_instructions.sh +88 -0
  56. package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_build_env.sh +114 -0
  57. package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_feedback_loops.sh +133 -0
  58. package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_policy.sh +113 -0
  59. package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_workflows.sh +127 -0
  60. package/plugins/onboarding/skills/improve-agent-readiness/README.md +19 -0
  61. package/plugins/onboarding/skills/improve-agent-readiness/SKILL.md +167 -0
  62. package/plugins/onboarding/skills/setup-agents-md/README.md +15 -0
  63. package/plugins/onboarding/skills/setup-agents-md/SKILL.md +150 -0
  64. package/plugins/onboarding/skills/setup-openhands/README.md +20 -0
  65. package/plugins/onboarding/skills/setup-openhands/SKILL.md +56 -0
  66. package/plugins/onboarding/skills/setup-pr-review/README.md +23 -0
  67. package/plugins/onboarding/skills/setup-pr-review/SKILL.md +72 -0
  68. package/plugins/openhands/.plugin/plugin.json +13 -0
  69. package/plugins/openhands/README.md +52 -0
  70. package/plugins/openhands/SKILL.md +61 -0
  71. package/plugins/openhands/commands/create.md +55 -0
  72. package/plugins/openhands/commands/openhands-cloud.md +8 -0
  73. package/plugins/openhands/scripts/run.sh +69 -0
  74. package/plugins/pr-review/.plugin/plugin.json +13 -0
  75. package/plugins/pr-review/README.md +393 -0
  76. package/plugins/pr-review/action.yml +298 -0
  77. package/plugins/pr-review/scripts/agent_script.py +1282 -0
  78. package/plugins/pr-review/scripts/evaluate_review.py +655 -0
  79. package/plugins/pr-review/scripts/prompt.py +260 -0
  80. package/plugins/pr-review/workflows/pr-review-by-openhands.yml +51 -0
  81. package/plugins/pr-review/workflows/pr-review-evaluation.yml +85 -0
  82. package/plugins/qa-changes/.plugin/plugin.json +11 -0
  83. package/plugins/qa-changes/README.md +185 -0
  84. package/plugins/qa-changes/action.yml +181 -0
  85. package/plugins/qa-changes/scripts/agent_script.py +406 -0
  86. package/plugins/qa-changes/scripts/evaluate_qa_changes.py +385 -0
  87. package/plugins/qa-changes/scripts/prompt.py +174 -0
  88. package/plugins/qa-changes/workflows/qa-changes-by-openhands.yml +50 -0
  89. package/plugins/qa-changes/workflows/qa-changes-evaluation.yml +85 -0
  90. package/plugins/release-notes/.plugin/plugin.json +19 -0
  91. package/plugins/release-notes/README.md +283 -0
  92. package/plugins/release-notes/SKILL.md +83 -0
  93. package/plugins/release-notes/action.yml +117 -0
  94. package/plugins/release-notes/commands/release-notes.md +8 -0
  95. package/plugins/release-notes/scripts/agent_script.py +292 -0
  96. package/plugins/release-notes/scripts/generate_release_notes.py +733 -0
  97. package/plugins/release-notes/scripts/prompt.py +90 -0
  98. package/plugins/release-notes/scripts/validate_release_notes.py +328 -0
  99. package/plugins/release-notes/workflows/release-notes.yml +76 -0
  100. package/plugins/vulnerability-remediation/.plugin/plugin.json +19 -0
  101. package/plugins/vulnerability-remediation/README.md +217 -0
  102. package/plugins/vulnerability-remediation/action.yml +187 -0
  103. package/plugins/vulnerability-remediation/scripts/scan_and_remediate.py +561 -0
  104. package/plugins/vulnerability-remediation/workflows/vulnerability-scan.yml +87 -0
  105. package/pyproject.toml +12 -0
  106. package/release-please-config.json +16 -0
  107. package/scripts/sync_extensions.py +494 -0
  108. package/scripts/sync_openhands_sdk_skill.py +264 -0
  109. package/skills/README.md +159 -0
  110. package/skills/add-javadoc/.plugin/plugin.json +18 -0
  111. package/skills/add-javadoc/README.md +40 -0
  112. package/skills/add-javadoc/SKILL.md +35 -0
  113. package/skills/add-javadoc/references/example.md +32 -0
  114. package/skills/add-skill/.plugin/plugin.json +18 -0
  115. package/skills/add-skill/README.md +67 -0
  116. package/skills/add-skill/SKILL.md +47 -0
  117. package/skills/add-skill/scripts/fetch_skill.py +259 -0
  118. package/skills/agent-creator/.plugin/plugin.json +20 -0
  119. package/skills/agent-creator/README.md +104 -0
  120. package/skills/agent-creator/SKILL.md +190 -0
  121. package/skills/agent-creator/commands/agent-creator.md +8 -0
  122. package/skills/agent-creator/references/fallback.md +117 -0
  123. package/skills/agent-memory/.plugin/plugin.json +18 -0
  124. package/skills/agent-memory/README.md +35 -0
  125. package/skills/agent-memory/SKILL.md +30 -0
  126. package/skills/agent-memory/commands/remember.md +8 -0
  127. package/skills/agent-sdk-builder/.plugin/plugin.json +18 -0
  128. package/skills/agent-sdk-builder/README.md +40 -0
  129. package/skills/agent-sdk-builder/SKILL.md +37 -0
  130. package/skills/agent-sdk-builder/commands/agent-builder.md +8 -0
  131. package/skills/azure-devops/.plugin/plugin.json +18 -0
  132. package/skills/azure-devops/README.md +55 -0
  133. package/skills/azure-devops/SKILL.md +50 -0
  134. package/skills/bitbucket/.plugin/plugin.json +17 -0
  135. package/skills/bitbucket/README.md +50 -0
  136. package/skills/bitbucket/SKILL.md +45 -0
  137. package/skills/code-review/.plugin/plugin.json +19 -0
  138. package/skills/code-review/README.md +18 -0
  139. package/skills/code-review/SKILL.md +208 -0
  140. package/skills/code-review/commands/codereview-roasted.md +8 -0
  141. package/skills/code-review/commands/codereview.md +8 -0
  142. package/skills/code-review/references/risk-evaluation.md +41 -0
  143. package/skills/code-review/references/supply-chain-security.md +31 -0
  144. package/skills/code-simplifier/.plugin/plugin.json +21 -0
  145. package/skills/code-simplifier/README.md +30 -0
  146. package/skills/code-simplifier/SKILL.md +91 -0
  147. package/skills/code-simplifier/commands/simplify.md +8 -0
  148. package/skills/code-simplifier/references/code-quality-review.md +86 -0
  149. package/skills/code-simplifier/references/code-reuse-review.md +63 -0
  150. package/skills/code-simplifier/references/efficiency-review.md +81 -0
  151. package/skills/datadog/.plugin/plugin.json +19 -0
  152. package/skills/datadog/README.md +100 -0
  153. package/skills/datadog/SKILL.md +95 -0
  154. package/skills/deno/.plugin/plugin.json +18 -0
  155. package/skills/deno/README.md +5 -0
  156. package/skills/deno/SKILL.md +99 -0
  157. package/skills/deno/references/README.md +6 -0
  158. package/skills/discord/.plugin/plugin.json +18 -0
  159. package/skills/discord/README.md +31 -0
  160. package/skills/discord/SKILL.md +109 -0
  161. package/skills/discord/__init__.py +0 -0
  162. package/skills/discord/references/REFERENCE.md +78 -0
  163. package/skills/discord/scripts/__init__.py +0 -0
  164. package/skills/discord/scripts/_http.py +127 -0
  165. package/skills/discord/scripts/post_webhook.py +106 -0
  166. package/skills/discord/scripts/send_message.py +102 -0
  167. package/skills/docker/.plugin/plugin.json +17 -0
  168. package/skills/docker/README.md +34 -0
  169. package/skills/docker/SKILL.md +29 -0
  170. package/skills/evidence-based-citations/.plugin/plugin.json +20 -0
  171. package/skills/evidence-based-citations/README.md +31 -0
  172. package/skills/evidence-based-citations/SKILL.md +59 -0
  173. package/skills/flarglebargle/.plugin/plugin.json +16 -0
  174. package/skills/flarglebargle/README.md +14 -0
  175. package/skills/flarglebargle/SKILL.md +9 -0
  176. package/skills/frontend-design/.plugin/plugin.json +21 -0
  177. package/skills/frontend-design/LICENSE.txt +177 -0
  178. package/skills/frontend-design/README.md +42 -0
  179. package/skills/frontend-design/SKILL.md +42 -0
  180. package/skills/github/.plugin/plugin.json +19 -0
  181. package/skills/github/README.md +42 -0
  182. package/skills/github/SKILL.md +106 -0
  183. package/skills/github-pr-review/.plugin/plugin.json +18 -0
  184. package/skills/github-pr-review/README.md +145 -0
  185. package/skills/github-pr-review/SKILL.md +148 -0
  186. package/skills/github-pr-review/commands/github-pr-review.md +8 -0
  187. package/skills/github-pr-reviewer/.plugin/plugin.json +20 -0
  188. package/skills/github-pr-reviewer/README.md +34 -0
  189. package/skills/github-pr-reviewer/SKILL.md +89 -0
  190. package/skills/github-pr-reviewer/commands/pr-reviewer:setup.md +8 -0
  191. package/skills/github-repo-monitor/.plugin/plugin.json +22 -0
  192. package/skills/github-repo-monitor/README.md +70 -0
  193. package/skills/github-repo-monitor/SKILL.md +316 -0
  194. package/skills/github-repo-monitor/commands/github-monitor:poll.md +8 -0
  195. package/skills/github-repo-monitor/references/github-api.md +241 -0
  196. package/skills/github-repo-monitor/references/state-schema.md +160 -0
  197. package/skills/github-repo-monitor/scripts/main.py +915 -0
  198. package/skills/github-repo-monitor/tests/test_main.py +400 -0
  199. package/skills/gitlab/.plugin/plugin.json +17 -0
  200. package/skills/gitlab/README.md +37 -0
  201. package/skills/gitlab/SKILL.md +32 -0
  202. package/skills/incident-retrospective/.plugin/plugin.json +21 -0
  203. package/skills/incident-retrospective/README.md +34 -0
  204. package/skills/incident-retrospective/SKILL.md +98 -0
  205. package/skills/incident-retrospective/commands/incident-retro:setup.md +8 -0
  206. package/skills/iterate/.plugin/plugin.json +13 -0
  207. package/skills/iterate/README.md +25 -0
  208. package/skills/iterate/SKILL.md +399 -0
  209. package/skills/iterate/commands/babysit.md +8 -0
  210. package/skills/iterate/commands/iterate.md +8 -0
  211. package/skills/iterate/commands/verify.md +8 -0
  212. package/skills/iterate/references/heuristics.md +58 -0
  213. package/skills/iterate/references/verification.md +96 -0
  214. package/skills/jupyter/.plugin/plugin.json +18 -0
  215. package/skills/jupyter/README.md +55 -0
  216. package/skills/jupyter/SKILL.md +50 -0
  217. package/skills/kubernetes/.plugin/plugin.json +18 -0
  218. package/skills/kubernetes/README.md +53 -0
  219. package/skills/kubernetes/SKILL.md +48 -0
  220. package/skills/learn-from-code-review/.plugin/plugin.json +19 -0
  221. package/skills/learn-from-code-review/README.md +64 -0
  222. package/skills/learn-from-code-review/SKILL.md +186 -0
  223. package/skills/learn-from-code-review/commands/learn-from-reviews.md +8 -0
  224. package/skills/linear/.plugin/plugin.json +19 -0
  225. package/skills/linear/README.md +58 -0
  226. package/skills/linear/SKILL.md +213 -0
  227. package/skills/linear-triage/.plugin/plugin.json +21 -0
  228. package/skills/linear-triage/README.md +34 -0
  229. package/skills/linear-triage/SKILL.md +91 -0
  230. package/skills/linear-triage/commands/linear-triage:setup.md +8 -0
  231. package/skills/notion/.plugin/plugin.json +17 -0
  232. package/skills/notion/README.md +114 -0
  233. package/skills/notion/SKILL.md +109 -0
  234. package/skills/npm/.plugin/plugin.json +17 -0
  235. package/skills/npm/README.md +14 -0
  236. package/skills/npm/SKILL.md +9 -0
  237. package/skills/openhands-api/.plugin/plugin.json +22 -0
  238. package/skills/openhands-api/README.md +48 -0
  239. package/skills/openhands-api/SKILL.md +399 -0
  240. package/skills/openhands-api/references/README.md +33 -0
  241. package/skills/openhands-api/references/TROUBLESHOOTING.md +81 -0
  242. package/skills/openhands-api/references/example_prompt.md +12 -0
  243. package/skills/openhands-api/scripts/openhands_api.py +606 -0
  244. package/skills/openhands-api/scripts/openhands_api.ts +252 -0
  245. package/skills/openhands-automation/.plugin/plugin.json +19 -0
  246. package/skills/openhands-automation/README.md +89 -0
  247. package/skills/openhands-automation/SKILL.md +875 -0
  248. package/skills/openhands-automation/commands/automation:create.md +8 -0
  249. package/skills/openhands-automation/references/ab-testing.md +185 -0
  250. package/skills/openhands-automation/references/custom-automation.md +644 -0
  251. package/skills/openhands-sdk/.plugin/plugin.json +20 -0
  252. package/skills/openhands-sdk/README.md +22 -0
  253. package/skills/openhands-sdk/SKILL.md +229 -0
  254. package/skills/openhands-sdk/commands/sdk.md +8 -0
  255. package/skills/pdflatex/.plugin/plugin.json +18 -0
  256. package/skills/pdflatex/README.md +39 -0
  257. package/skills/pdflatex/SKILL.md +34 -0
  258. package/skills/prd/.plugin/plugin.json +19 -0
  259. package/skills/prd/README.md +28 -0
  260. package/skills/prd/SKILL.md +237 -0
  261. package/skills/prd/commands/prd.md +8 -0
  262. package/skills/qa-changes/README.md +18 -0
  263. package/skills/qa-changes/SKILL.md +229 -0
  264. package/skills/qa-changes/commands/qa-changes.md +8 -0
  265. package/skills/release-notes/README.md +24 -0
  266. package/skills/release-notes/SKILL.md +19 -0
  267. package/skills/release-notes/commands/release-notes.md +8 -0
  268. package/skills/research-brief/.plugin/plugin.json +20 -0
  269. package/skills/research-brief/README.md +34 -0
  270. package/skills/research-brief/SKILL.md +99 -0
  271. package/skills/research-brief/commands/research-brief:setup.md +8 -0
  272. package/skills/security/.plugin/plugin.json +18 -0
  273. package/skills/security/README.md +38 -0
  274. package/skills/security/SKILL.md +33 -0
  275. package/skills/skill-creator/.plugin/plugin.json +17 -0
  276. package/skills/skill-creator/LICENSE.txt +202 -0
  277. package/skills/skill-creator/README.md +182 -0
  278. package/skills/skill-creator/SKILL.md +545 -0
  279. package/skills/skill-creator/references/output-patterns.md +82 -0
  280. package/skills/skill-creator/references/workflows.md +28 -0
  281. package/skills/skill-creator/scripts/init_skill.py +303 -0
  282. package/skills/skill-creator/scripts/quick_validate.py +95 -0
  283. package/skills/slack-channel-monitor/.plugin/plugin.json +21 -0
  284. package/skills/slack-channel-monitor/README.md +91 -0
  285. package/skills/slack-channel-monitor/SKILL.md +276 -0
  286. package/skills/slack-channel-monitor/commands/slack-monitor:poll.md +8 -0
  287. package/skills/slack-channel-monitor/references/slack-api.md +207 -0
  288. package/skills/slack-channel-monitor/references/state-schema.md +180 -0
  289. package/skills/slack-channel-monitor/scripts/main.py +962 -0
  290. package/skills/slack-standup-digest/.plugin/plugin.json +21 -0
  291. package/skills/slack-standup-digest/README.md +34 -0
  292. package/skills/slack-standup-digest/SKILL.md +92 -0
  293. package/skills/slack-standup-digest/commands/standup-digest:setup.md +8 -0
  294. package/skills/spark-version-upgrade/.plugin/plugin.json +20 -0
  295. package/skills/spark-version-upgrade/README.md +54 -0
  296. package/skills/spark-version-upgrade/SKILL.md +233 -0
  297. package/skills/ssh/.plugin/plugin.json +18 -0
  298. package/skills/ssh/README.md +140 -0
  299. package/skills/ssh/SKILL.md +135 -0
  300. package/skills/swift-linux/.plugin/plugin.json +17 -0
  301. package/skills/swift-linux/README.md +86 -0
  302. package/skills/swift-linux/SKILL.md +81 -0
  303. package/skills/theme-factory/.plugin/plugin.json +19 -0
  304. package/skills/theme-factory/LICENSE.txt +202 -0
  305. package/skills/theme-factory/README.md +58 -0
  306. package/skills/theme-factory/SKILL.md +59 -0
  307. package/skills/theme-factory/theme-showcase.pdf +0 -0
  308. package/skills/theme-factory/themes/arctic-frost.md +19 -0
  309. package/skills/theme-factory/themes/botanical-garden.md +19 -0
  310. package/skills/theme-factory/themes/desert-rose.md +19 -0
  311. package/skills/theme-factory/themes/forest-canopy.md +19 -0
  312. package/skills/theme-factory/themes/golden-hour.md +19 -0
  313. package/skills/theme-factory/themes/midnight-galaxy.md +19 -0
  314. package/skills/theme-factory/themes/modern-minimalist.md +19 -0
  315. package/skills/theme-factory/themes/ocean-depths.md +19 -0
  316. package/skills/theme-factory/themes/sunset-boulevard.md +19 -0
  317. package/skills/theme-factory/themes/tech-innovation.md +19 -0
  318. package/skills/uv/.plugin/plugin.json +18 -0
  319. package/skills/uv/README.md +5 -0
  320. package/skills/uv/SKILL.md +95 -0
  321. package/skills/uv/references/README.md +5 -0
  322. package/skills/vercel/.plugin/plugin.json +18 -0
  323. package/skills/vercel/README.md +108 -0
  324. package/skills/vercel/SKILL.md +103 -0
  325. package/tests/test_add_skill_installs_to_agents_dir.py +42 -0
  326. package/tests/test_catalogs.py +109 -0
  327. package/tests/test_code_review_risk_evaluation.py +94 -0
  328. package/tests/test_issue_duplicate_checker.py +240 -0
  329. package/tests/test_openhands_api_python.py +152 -0
  330. package/tests/test_plugin_manifest.py +83 -0
  331. package/tests/test_pr_review_diff_payload.py +202 -0
  332. package/tests/test_pr_review_feedback.py +263 -0
  333. package/tests/test_pr_review_prompt.py +152 -0
  334. package/tests/test_pr_review_review_context.py +253 -0
  335. package/tests/test_qa_changes.py +232 -0
  336. package/tests/test_qa_changes_evaluation.py +259 -0
  337. package/tests/test_release_notes_generator.py +990 -0
  338. package/tests/test_sdk_loading.py +150 -0
  339. package/tests/test_skill_plugin_loading.py +149 -0
  340. package/tests/test_skills_have_readme.py +66 -0
  341. package/tests/test_sync_extensions.py +292 -0
  342. package/tests/test_workflow_sync.py +46 -0
  343. package/utils/analysis/README.md +7 -0
  344. package/utils/analysis/laminar_signals/README.md +211 -0
  345. package/utils/analysis/laminar_signals/analyze.py +780 -0
  346. package/utils/analysis/laminar_signals/templates/default.j2 +49 -0
  347. package/utils/analysis/laminar_signals/templates/pr_review.j2 +61 -0
@@ -0,0 +1,220 @@
1
+ module.exports = async ({ github, context, core }) => {
2
+ const issueNumber = Number(process.env.ISSUE_NUMBER);
3
+ const summary = (process.env.SUMMARY || "").trim();
4
+ const classification = process.env.CLASSIFICATION || "no-match";
5
+ const autoClose = process.env.AUTO_CLOSE_CANDIDATE === "true";
6
+ const closeAfterDays = process.env.CLOSE_AFTER_DAYS || "3";
7
+ let candidates = [];
8
+ try {
9
+ candidates = JSON.parse(process.env.CANDIDATE_ISSUES_JSON || "[]");
10
+ } catch (error) {
11
+ core.setFailed(`Invalid candidate JSON: ${error.message}`);
12
+ return;
13
+ }
14
+ if (!Array.isArray(candidates)) {
15
+ core.setFailed("CANDIDATE_ISSUES_JSON is not an array");
16
+ return;
17
+ }
18
+ if (candidates.length === 0) {
19
+ core.warning(`No candidate issues were returned for issue #${issueNumber}; skipping.`);
20
+ return;
21
+ }
22
+
23
+ const canonicalIssueRaw = process.env.CANONICAL_ISSUE_NUMBER || candidates[0].number;
24
+ const canonicalIssueNumber = canonicalIssueRaw ? Number(canonicalIssueRaw) : Number.NaN;
25
+ const candidateLabel = "duplicate-candidate";
26
+
27
+ function parseDuplicateCheckMarker(body) {
28
+ if (!body) return null;
29
+ const match = body.match(/<!-- openhands-duplicate-check canonical=(\d+) auto-close=(true|false) -->/);
30
+ if (!match) return null;
31
+ return {
32
+ canonicalIssueNumber: Number(match[1]),
33
+ autoClose: match[2] === "true",
34
+ };
35
+ }
36
+
37
+ async function ensureCanonicalIssueIsOpenIssue() {
38
+ let canonicalIssue;
39
+ try {
40
+ ({ data: canonicalIssue } = await github.rest.issues.get({
41
+ owner: context.repo.owner,
42
+ repo: context.repo.repo,
43
+ issue_number: canonicalIssueNumber,
44
+ }));
45
+ } catch (error) {
46
+ if (error.status === 404) {
47
+ core.setFailed(`Canonical issue #${canonicalIssueNumber} does not exist.`);
48
+ return false;
49
+ }
50
+ throw error;
51
+ }
52
+ if (canonicalIssue.pull_request) {
53
+ core.setFailed(`Canonical issue #${canonicalIssueNumber} is a pull request, not an issue.`);
54
+ return false;
55
+ }
56
+ if (canonicalIssue.state !== "open" || canonicalIssue.locked) {
57
+ core.setFailed(`Canonical issue #${canonicalIssueNumber} must be an open, unlocked issue.`);
58
+ return false;
59
+ }
60
+ return true;
61
+ }
62
+
63
+ async function ensureCandidateLabelOnIssue() {
64
+ try {
65
+ await github.rest.issues.getLabel({
66
+ owner: context.repo.owner,
67
+ repo: context.repo.repo,
68
+ name: candidateLabel,
69
+ });
70
+ } catch (error) {
71
+ if (error.status !== 404) throw error;
72
+ await github.rest.issues.createLabel({
73
+ owner: context.repo.owner,
74
+ repo: context.repo.repo,
75
+ name: candidateLabel,
76
+ color: "f97316",
77
+ description: "Potential duplicate awaiting auto-close or maintainer review",
78
+ });
79
+ }
80
+
81
+ const { data: issue } = await github.rest.issues.get({
82
+ owner: context.repo.owner,
83
+ repo: context.repo.repo,
84
+ issue_number: issueNumber,
85
+ });
86
+ const labelNames = (issue.labels || []).map((label) =>
87
+ typeof label === "string" ? label : label.name,
88
+ );
89
+ if (!labelNames.includes(candidateLabel)) {
90
+ await github.rest.issues.addLabels({
91
+ owner: context.repo.owner,
92
+ repo: context.repo.repo,
93
+ issue_number: issueNumber,
94
+ labels: [candidateLabel],
95
+ });
96
+ }
97
+ }
98
+
99
+ async function removeCandidateLabelFromIssue() {
100
+ try {
101
+ await github.rest.issues.removeLabel({
102
+ owner: context.repo.owner,
103
+ repo: context.repo.repo,
104
+ issue_number: issueNumber,
105
+ name: candidateLabel,
106
+ });
107
+ } catch (error) {
108
+ if (error.status !== 404) throw error;
109
+ }
110
+ }
111
+
112
+ if (!Number.isInteger(canonicalIssueNumber) || canonicalIssueNumber <= 0) {
113
+ core.setFailed(`No canonical issue number was returned for issue #${issueNumber}.`);
114
+ return;
115
+ }
116
+ if (canonicalIssueNumber === issueNumber) {
117
+ core.setFailed(`Duplicate check cannot mark issue #${issueNumber} as a duplicate of itself.`);
118
+ return;
119
+ }
120
+
121
+ if (!(await ensureCanonicalIssueIsOpenIssue())) return;
122
+
123
+ const marker = `<!-- openhands-duplicate-check canonical=${canonicalIssueNumber} auto-close=${autoClose ? "true" : "false"} -->`;
124
+ const header = candidates.length === 1
125
+ ? "Found 1 possible duplicate issue:"
126
+ : `Found ${candidates.length} possible duplicate issues:`;
127
+ const candidateLines = candidates.map((candidate, index) =>
128
+ `${index + 1}. [#${candidate.number}](${candidate.url}) — ${candidate.title}`,
129
+ );
130
+
131
+ const sections = [];
132
+ if (summary) sections.push(summary, "");
133
+ sections.push(header, "", ...candidateLines);
134
+
135
+ if (classification === "overlapping-scope") {
136
+ sections.push(
137
+ "",
138
+ "These may not be exact duplicates, but the scope appears to overlap enough that keeping discussion in one place may be more useful.",
139
+ );
140
+ }
141
+
142
+ if (autoClose) {
143
+ sections.push(
144
+ "",
145
+ `This issue will be automatically closed as a duplicate in ${closeAfterDays} days.`,
146
+ "",
147
+ "- If your issue is a duplicate, please close it and 👍 the existing issue instead",
148
+ "- To prevent auto-closure, add a comment or 👎 this comment",
149
+ );
150
+ }
151
+
152
+ sections.push(
153
+ "",
154
+ marker,
155
+ "_This comment was created by an AI assistant (OpenHands) on behalf of the repository maintainer._",
156
+ );
157
+ const body = sections.join("\n").trim();
158
+
159
+ const maxCommentPages = 50;
160
+ let allComments = [];
161
+ let page = 1;
162
+ while (page <= maxCommentPages) {
163
+ const { data: comments } = await github.rest.issues.listComments({
164
+ owner: context.repo.owner,
165
+ repo: context.repo.repo,
166
+ issue_number: issueNumber,
167
+ per_page: 100,
168
+ page,
169
+ });
170
+ if (!comments || comments.length === 0) break;
171
+ allComments = allComments.concat(comments);
172
+ if (comments.length < 100) break;
173
+ page += 1;
174
+ }
175
+ if (page > maxCommentPages) {
176
+ core.setFailed(`Stopped loading comments for issue #${issueNumber} after ${maxCommentPages} pages.`);
177
+ return;
178
+ }
179
+
180
+ const existing = allComments.find((comment) =>
181
+ comment.body && comment.body.includes("<!-- openhands-duplicate-check "),
182
+ );
183
+ if (existing) {
184
+ const existingMarker = parseDuplicateCheckMarker(existing.body);
185
+ if (existingMarker) {
186
+ if (
187
+ existingMarker.canonicalIssueNumber !== canonicalIssueNumber ||
188
+ existingMarker.autoClose !== autoClose
189
+ ) {
190
+ await github.rest.issues.updateComment({
191
+ owner: context.repo.owner,
192
+ repo: context.repo.repo,
193
+ comment_id: existing.id,
194
+ body,
195
+ });
196
+ if (autoClose) await ensureCandidateLabelOnIssue();
197
+ else await removeCandidateLabelFromIssue();
198
+ core.info(`Updated existing duplicate check comment ${existing.id} on issue #${issueNumber}.`);
199
+ return;
200
+ }
201
+ if (autoClose) await ensureCandidateLabelOnIssue();
202
+ else await removeCandidateLabelFromIssue();
203
+ } else {
204
+ core.warning(
205
+ `Duplicate check comment already exists on issue #${issueNumber} but its marker could not be parsed; leaving label state unchanged.`,
206
+ );
207
+ }
208
+ core.info(`Duplicate check comment already exists on issue #${issueNumber}; skipping.`);
209
+ return;
210
+ }
211
+
212
+ await github.rest.issues.createComment({
213
+ owner: context.repo.owner,
214
+ repo: context.repo.repo,
215
+ issue_number: issueNumber,
216
+ body,
217
+ });
218
+
219
+ if (autoClose) await ensureCandidateLabelOnIssue();
220
+ };
@@ -0,0 +1,27 @@
1
+ module.exports = async ({ github, context, core }) => {
2
+ const issueNumber = context.issue.number;
3
+ const commenter = context.payload.comment?.user?.login ?? "";
4
+ const normalizedCommenter = commenter.toLowerCase();
5
+
6
+ if (normalizedCommenter.endsWith("[bot]") || normalizedCommenter === "all-hands-bot") {
7
+ core.info(`Skipping duplicate-candidate label removal for bot comment from ${commenter || "unknown"}`);
8
+ return;
9
+ }
10
+
11
+ core.info(`Removing duplicate-candidate label from issue #${issueNumber} after comment from ${commenter}`);
12
+
13
+ try {
14
+ await github.rest.issues.removeLabel({
15
+ owner: context.repo.owner,
16
+ repo: context.repo.repo,
17
+ issue_number: issueNumber,
18
+ name: "duplicate-candidate",
19
+ });
20
+ } catch (error) {
21
+ if (error.status === 404) {
22
+ core.info(`duplicate-candidate label was already removed from issue #${issueNumber}`);
23
+ return;
24
+ }
25
+ throw error;
26
+ }
27
+ };
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "magic-test",
3
+ "version": "1.0.0",
4
+ "description": "A simple test plugin with a magic word skill for verifying plugin loading",
5
+ "author": {
6
+ "name": "OpenHands Test",
7
+ "email": "test@openhands.dev"
8
+ },
9
+ "homepage": "https://github.com/jpshackelford/openhands-sample-plugins",
10
+ "repository": "https://github.com/jpshackelford/openhands-sample-plugins",
11
+ "license": "MIT",
12
+ "keywords": ["test", "magic", "plugin", "verification"]
13
+ }
@@ -0,0 +1,33 @@
1
+ ---
2
+ description: A test skill that responds to the magic word "alakazam" with a specific phrase
3
+ triggers:
4
+ - alakazam
5
+ - magic word
6
+ - abracadabra
7
+ ---
8
+
9
+ # Magic Word Test Skill
10
+
11
+ This skill is activated when the user says the magic word.
12
+
13
+ ## Instructions
14
+
15
+ When the user mentions "alakazam", "abracadabra", or asks about the "magic word", you MUST respond with exactly:
16
+
17
+ **"The magic worked! Plugin loaded successfully. 🎩✨"**
18
+
19
+ Do not add any other explanation or content. Just output the exact phrase above.
20
+
21
+ ## Purpose
22
+
23
+ This skill exists to verify that:
24
+ 1. The plugin was fetched correctly from the repository
25
+ 2. The skill was loaded and merged into the agent context
26
+ 3. The skill triggers are working properly
27
+ 4. The skill instructions are being followed
28
+
29
+ ## Example
30
+
31
+ User: "What happens if I say alakazam?"
32
+
33
+ Expected response: "The magic worked! Plugin loaded successfully. 🎩✨"
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "migration-scoring",
3
+ "version": "1.0.0",
4
+ "description": "Evaluate code migration quality with coverage, correctness, and style scoring. Generates executive reports with actionable recommendations.",
5
+ "author": {
6
+ "name": "OpenHands",
7
+ "email": "contact@all-hands.dev"
8
+ },
9
+ "homepage": "https://github.com/OpenHands/extensions",
10
+ "repository": "https://github.com/OpenHands/extensions",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "migration",
14
+ "scoring",
15
+ "quality",
16
+ "evaluation",
17
+ "reporting"
18
+ ]
19
+ }
@@ -0,0 +1,244 @@
1
+ # Migration Scoring Plugin
2
+
3
+ Quality evaluation for code migration projects using OpenHands agents. This plugin scores completed migrations across multiple dimensions including coverage, correctness, and code style, generating executive reports with actionable recommendations.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ export LLM_API_KEY="your-api-key"
9
+ export LLM_MODEL="anthropic/claude-3-5-sonnet-20241022"
10
+
11
+ uv run python -m lc_sdk_examples.migration_scoring \
12
+ --src-path /path/to/migration/project \
13
+ --rubric-path /path/to/style_rubric.txt
14
+ ```
15
+
16
+ ## Features
17
+
18
+ - **Multi-Dimensional Scoring** — Evaluates coverage, correctness, and style separately
19
+ - **Source-to-Target Mapping** — Documents relationships between source and migrated files
20
+ - **Executive Reporting** — Generates summary reports with risk categorization
21
+ - **Custom Style Rubrics** — Supports project-specific style guidelines
22
+ - **Actionable Recommendations** — Prioritized list of improvements
23
+
24
+ ## Prerequisites
25
+
26
+ - Completed migration with both source and target code present
27
+ - Python 3.13 with `uv`
28
+ - LLM API key (Anthropic or OpenAI)
29
+ - Optional: Custom style rubric file
30
+
31
+ ## Plugin Contents
32
+
33
+ ```
34
+ plugins/migration-scoring/
35
+ ├── README.md # This file
36
+ └── skills/ # Workflow phase skills
37
+ ├── migration-scoring-overview/ # Plugin overview
38
+ │ └── SKILL.md
39
+ ├── migration-mapping/ # Phase 1: Source-to-target mapping
40
+ │ └── SKILL.md
41
+ ├── score-quality/ # Phase 2: Coverage and correctness
42
+ │ ├── SKILL.md
43
+ │ └── references/
44
+ │ └── scoring-criteria.md
45
+ ├── score-style/ # Phase 3: Code style evaluation
46
+ │ └── SKILL.md
47
+ └── migration-report/ # Phase 4: Executive report
48
+ └── SKILL.md
49
+ ```
50
+
51
+ ## Workflow Phases
52
+
53
+ ### Phase 1: Migration Mapping
54
+
55
+ Creates a source→target file mapping:
56
+
57
+ - Identifies which target files implement each source file
58
+ - Supports many-to-many relationships
59
+ - Flags unmigrated source files
60
+
61
+ **Output:** `migration_mapping.json`
62
+
63
+ ```json
64
+ {
65
+ "CALC001.cbl": ["InvoiceCalculator.java", "TaxCalculator.java"],
66
+ "CUST002.cbl": ["CustomerService.java"]
67
+ }
68
+ ```
69
+
70
+ ### Phase 2: Quality Scoring
71
+
72
+ Scores each source file on:
73
+
74
+ - **Coverage (1-5)**: How much functionality was migrated
75
+ - **Correctness (1-5)**: How accurately behavior was preserved
76
+
77
+ **Output:** `migration_score.json`
78
+
79
+ ```json
80
+ {
81
+ "CALC001.cbl": {
82
+ "coverage": 4,
83
+ "correctness": 5,
84
+ "justification": "All calculation logic migrated..."
85
+ }
86
+ }
87
+ ```
88
+
89
+ ### Phase 3: Style Scoring
90
+
91
+ Evaluates target code against style guidelines:
92
+
93
+ - Naming conventions
94
+ - Code organization
95
+ - Error handling
96
+ - Documentation
97
+ - Idiomaticity
98
+
99
+ **Output:** `style_score.json`
100
+
101
+ ### Phase 4: Executive Report
102
+
103
+ Generates a detailed report:
104
+
105
+ - Overall health assessment
106
+ - Score statistics and distribution
107
+ - Risk categorization (Green/Yellow/Red)
108
+ - Prioritized recommendations
109
+
110
+ **Output:** `final_report.md`
111
+
112
+ ## Output Structure
113
+
114
+ ```
115
+ your-project/
116
+ ├── .lc-sdk/
117
+ │ ├── migration_mapping.json
118
+ │ ├── migration_score.json
119
+ │ ├── style_score.json
120
+ │ └── final_report.md
121
+ ```
122
+
123
+ ## Usage
124
+
125
+ ### Running the Evaluation
126
+
127
+ 1. **Ensure migration is complete**: Both source and target code should be present
128
+ 2. **Set environment variables**:
129
+ ```bash
130
+ export LLM_API_KEY="your-api-key"
131
+ export LLM_MODEL="anthropic/claude-3-5-sonnet-20241022"
132
+ ```
133
+ 3. **Run the scoring**:
134
+ ```bash
135
+ uv run python -m lc_sdk_examples.migration_scoring \
136
+ --src-path /path/to/migration/project \
137
+ --rubric-path /path/to/style_rubric.txt
138
+ ```
139
+ 4. **Review the report**: Check `final_report.md` for results and recommendations
140
+
141
+ ### Using a Custom Style Rubric
142
+
143
+ Create a text file with your style guidelines:
144
+
145
+ ```text
146
+ # Style Rubric for Java Migration
147
+
148
+ ## Naming Conventions
149
+ - Use camelCase for methods and variables
150
+ - Use PascalCase for classes
151
+ - Avoid Hungarian notation
152
+
153
+ ## Code Organization
154
+ - One public class per file
155
+ - Group related methods together
156
+ - Maximum 500 lines per class
157
+
158
+ ## Error Handling
159
+ - Use specific exception types
160
+ - Include meaningful error messages
161
+ - Log exceptions appropriately
162
+ ```
163
+
164
+ Then pass it using `--rubric-path`:
165
+
166
+ ```bash
167
+ uv run python -m lc_sdk_examples.migration_scoring \
168
+ --src-path /path/to/project \
169
+ --rubric-path ./my_style_rubric.txt
170
+ ```
171
+
172
+ ## Scoring Criteria
173
+
174
+ ### Coverage Score (1-5)
175
+
176
+ | Score | Description |
177
+ |-------|-------------|
178
+ | 5 | 100% of source functionality migrated |
179
+ | 4 | 90%+ migrated, minor features missing |
180
+ | 3 | 70-90% migrated, some features missing |
181
+ | 2 | 50-70% migrated, significant gaps |
182
+ | 1 | Less than 50% migrated |
183
+
184
+ ### Correctness Score (1-5)
185
+
186
+ | Score | Description |
187
+ |-------|-------------|
188
+ | 5 | Behavior exactly matches source |
189
+ | 4 | Minor edge case differences |
190
+ | 3 | Some behavioral differences |
191
+ | 2 | Significant behavioral changes |
192
+ | 1 | Major functionality broken |
193
+
194
+ ### Risk Categories
195
+
196
+ - **Green**: All scores ≥ 4 — Migration is production-ready
197
+ - **Yellow**: Any score 3-4 — Needs review before production
198
+ - **Red**: Any score < 3 — Significant work required
199
+
200
+ ## Troubleshooting
201
+
202
+ ### Mapping Not Found
203
+
204
+ 1. Verify directory structure matches expected layout
205
+ 2. Check file extensions are recognized
206
+ 3. Ensure source and target directories are accessible
207
+
208
+ ### Low Coverage Scores
209
+
210
+ 1. Review unmigrated files in the mapping
211
+ 2. Check for split functionality across multiple target files
212
+ 3. Verify all helper/utility functions are included
213
+
214
+ ### Style Score Issues
215
+
216
+ 1. Check that rubric file is valid
217
+ 2. Verify target code files are readable
218
+ 3. Review specific style violations in `style_score.json`
219
+
220
+ ### Report Generation Fails
221
+
222
+ 1. Ensure all previous phases completed successfully
223
+ 2. Check that score JSON files are valid
224
+ 3. Verify sufficient disk space for output
225
+
226
+ ## Integration with COBOL Modernization
227
+
228
+ This plugin works seamlessly with the [COBOL Modernization Plugin](../cobol-modernization/README.md):
229
+
230
+ ```bash
231
+ # First, run the migration
232
+ uv run python -m lc_sdk_examples.cobol_modernization --src-path /path/to/cobol
233
+
234
+ # Then, score the results
235
+ uv run python -m lc_sdk_examples.migration_scoring --src-path /path/to/cobol
236
+ ```
237
+
238
+ ## Contributing
239
+
240
+ See the main [extensions repository](https://github.com/OpenHands/extensions) for contribution guidelines.
241
+
242
+ ## License
243
+
244
+ This plugin is part of the OpenHands extensions repository. See [LICENSE](../../LICENSE) for details.
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: migration-mapping
3
+ description: Create a mapping from source language files to target language files for code migrations. Use when evaluating or documenting a migration project.
4
+ license: MIT
5
+ compatibility: Requires completed migration with source and target code
6
+ triggers:
7
+ - migration mapping
8
+ - source target mapping
9
+ - file mapping
10
+ ---
11
+
12
+ Create a mapping from source language files (e.g., COBOL) to target language files (e.g., Java) to document which target files implement the functionality of each source file.
13
+
14
+ ## Task
15
+
16
+ Examine all source language files and identify the corresponding target language files that implement the same functionality. This mapping is essential for:
17
+ - Migration quality evaluation
18
+ - Traceability documentation
19
+ - Gap analysis
20
+
21
+ ## Output Format
22
+
23
+ Save the mapping as a JSON file with this structure:
24
+
25
+ ```json
26
+ {
27
+ "source_file_1.cbl": ["target_file_a.java", "target_file_b.java"],
28
+ "source_file_2.cbl": ["target_file_c.java"],
29
+ "source_file_3.cbl": []
30
+ }
31
+ ```
32
+
33
+ ## Rules
34
+
35
+ 1. **Many-to-many mapping**: A source file may map to multiple target files, and a target file may implement logic from multiple source files
36
+ 2. **Complete coverage**: EVERY source file must appear as a key in the mapping
37
+ 3. **Complete target coverage**: EVERY target file should appear as a value at least once
38
+ 4. **Empty arrays**: If a source file has no corresponding target implementation, use an empty array `[]`
39
+ 5. **Incremental**: If a mapping file already exists, update it rather than replacing it
40
+
41
+ ## How to Identify Mappings
42
+
43
+ Look for:
44
+ - Matching class/program names
45
+ - Similar function/paragraph names
46
+ - Matching business logic patterns
47
+ - Comments referencing source files
48
+ - Import/include statements
49
+ - Data structure similarities
50
+
51
+ ## Example
52
+
53
+ For a COBOL-to-Java migration:
54
+
55
+ ```json
56
+ {
57
+ "CALC001.cbl": ["InvoiceCalculator.java", "TaxCalculator.java"],
58
+ "CUST002.cbl": ["CustomerService.java", "CustomerRepository.java"],
59
+ "UTIL003.cbl": ["StringUtils.java"],
60
+ "SCREEN001.cbl": []
61
+ }
62
+ ```
63
+
64
+ Note: `SCREEN001.cbl` maps to nothing because UI code was not migrated.
65
+
66
+ ## Verification
67
+
68
+ After creating the mapping:
69
+ - [ ] Every source file is a key
70
+ - [ ] No duplicate keys
71
+ - [ ] Target files are relative paths from project root
72
+ - [ ] JSON is valid and well-formatted