@openhands/extensions 0.20.0 → 0.22.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 (305) hide show
  1. package/.claude-plugin/marketplace.json +881 -0
  2. package/.codex-plugin/marketplace.json +881 -0
  3. package/.github/workflows/check-extensions.yml +4 -0
  4. package/.github/workflows/npm-publish.yml +9 -3
  5. package/.github/workflows/pr-artifacts.yml +294 -0
  6. package/.github/workflows/pr-description-check.yml +4 -2
  7. package/.plugin/marketplace.json +881 -0
  8. package/.release-please-manifest.json +1 -1
  9. package/AGENTS.md +27 -3
  10. package/README.md +6 -2
  11. package/automations/bundle-index.js +22 -3
  12. package/automations/catalog/github-agents-md-maintainer/manifest.json +2 -1
  13. package/automations/catalog/github-delivery-watchdog/manifest.json +79 -0
  14. package/automations/catalog/github-issue-to-pr/manifest.json +24 -15
  15. package/automations/catalog/github-issue-triage/manifest.json +73 -0
  16. package/automations/catalog/github-pr-reviewer/manifest.json +23 -15
  17. package/automations/catalog/gitlab-issue-to-mr/manifest.json +124 -0
  18. package/automations/catalog-index.js +17 -11
  19. package/integrations/catalog/reportportal.json +76 -0
  20. package/integrations/catalog-index.js +6 -4
  21. package/marketplaces/openhands-extensions.json +42 -0
  22. package/package.json +1 -1
  23. package/plugins/city-weather/.claude-plugin/plugin.json +13 -0
  24. package/plugins/city-weather/.codex-plugin/plugin.json +13 -0
  25. package/plugins/cobol-modernization/.claude-plugin/plugin.json +19 -0
  26. package/plugins/cobol-modernization/.codex-plugin/plugin.json +19 -0
  27. package/plugins/issue-duplicate-checker/.claude-plugin/plugin.json +13 -0
  28. package/plugins/issue-duplicate-checker/.codex-plugin/plugin.json +13 -0
  29. package/plugins/magic-test/.claude-plugin/plugin.json +13 -0
  30. package/plugins/magic-test/.codex-plugin/plugin.json +13 -0
  31. package/plugins/migration-scoring/.claude-plugin/plugin.json +19 -0
  32. package/plugins/migration-scoring/.codex-plugin/plugin.json +19 -0
  33. package/plugins/onboarding/.claude-plugin/plugin.json +20 -0
  34. package/plugins/onboarding/.codex-plugin/plugin.json +20 -0
  35. package/plugins/onboarding/skills/agent-readiness-report/references/criteria.md +144 -0
  36. package/plugins/onboarding/skills/improve-agent-readiness/references/criteria.md +144 -0
  37. package/plugins/openhands/.claude-plugin/plugin.json +13 -0
  38. package/plugins/openhands/.codex-plugin/plugin.json +13 -0
  39. package/plugins/openhands/skills/openhands-api/.claude-plugin/plugin.json +22 -0
  40. package/plugins/openhands/skills/openhands-api/.codex-plugin/plugin.json +22 -0
  41. package/plugins/openhands/skills/openhands-api/.plugin/plugin.json +22 -0
  42. package/plugins/openhands/skills/openhands-api/README.md +52 -0
  43. package/plugins/openhands/skills/openhands-api/SKILL.md +469 -0
  44. package/plugins/openhands/skills/openhands-api/references/README.md +33 -0
  45. package/plugins/openhands/skills/openhands-api/references/TROUBLESHOOTING.md +81 -0
  46. package/plugins/openhands/skills/openhands-api/references/example_prompt.md +12 -0
  47. package/plugins/openhands/skills/openhands-api/references/windows.md +44 -0
  48. package/plugins/openhands/skills/openhands-api/scripts/openhands_api.py +606 -0
  49. package/plugins/openhands/skills/openhands-api/scripts/openhands_api.ts +252 -0
  50. package/plugins/openhands/skills/openhands-automation/.claude-plugin/plugin.json +19 -0
  51. package/plugins/openhands/skills/openhands-automation/.codex-plugin/plugin.json +19 -0
  52. package/plugins/openhands/skills/openhands-automation/.plugin/plugin.json +19 -0
  53. package/plugins/openhands/skills/openhands-automation/README.md +89 -0
  54. package/plugins/openhands/skills/openhands-automation/SKILL.md +899 -0
  55. package/plugins/openhands/skills/openhands-automation/commands/automation-create.md +8 -0
  56. package/plugins/openhands/skills/openhands-automation/references/ab-testing.md +185 -0
  57. package/plugins/openhands/skills/openhands-automation/references/custom-automation.md +832 -0
  58. package/plugins/openhands/skills/openhands-automation/references/security.md +84 -0
  59. package/plugins/openhands/skills/openhands-automation/references/windows.md +57 -0
  60. package/plugins/openhands/skills/openhands-sdk/.claude-plugin/plugin.json +20 -0
  61. package/plugins/openhands/skills/openhands-sdk/.codex-plugin/plugin.json +20 -0
  62. package/plugins/openhands/skills/openhands-sdk/.plugin/plugin.json +20 -0
  63. package/plugins/openhands/skills/openhands-sdk/README.md +22 -0
  64. package/plugins/openhands/skills/openhands-sdk/SKILL.md +245 -0
  65. package/plugins/openhands/skills/openhands-sdk/commands/sdk.md +8 -0
  66. package/plugins/pr-review/.claude-plugin/plugin.json +13 -0
  67. package/plugins/pr-review/.codex-plugin/plugin.json +13 -0
  68. package/plugins/pr-review/skills/code-review/.claude-plugin/plugin.json +19 -0
  69. package/plugins/pr-review/skills/code-review/.codex-plugin/plugin.json +19 -0
  70. package/plugins/pr-review/skills/code-review/.plugin/plugin.json +19 -0
  71. package/plugins/pr-review/skills/code-review/README.md +18 -0
  72. package/plugins/pr-review/skills/code-review/SKILL.md +209 -0
  73. package/plugins/pr-review/skills/code-review/commands/codereview-roasted.md +8 -0
  74. package/plugins/pr-review/skills/code-review/commands/codereview.md +8 -0
  75. package/plugins/pr-review/skills/code-review/references/risk-evaluation.md +41 -0
  76. package/plugins/pr-review/skills/code-review/references/supply-chain-security.md +31 -0
  77. package/plugins/pr-review/skills/github-pr-review/.claude-plugin/plugin.json +18 -0
  78. package/plugins/pr-review/skills/github-pr-review/.codex-plugin/plugin.json +18 -0
  79. package/plugins/pr-review/skills/github-pr-review/.plugin/plugin.json +18 -0
  80. package/plugins/pr-review/skills/github-pr-review/README.md +145 -0
  81. package/plugins/pr-review/skills/github-pr-review/SKILL.md +187 -0
  82. package/plugins/pr-review/skills/github-pr-review/commands/github-pr-review.md +8 -0
  83. package/plugins/pr-review/skills/github-pr-review/references/windows.md +47 -0
  84. package/plugins/qa-changes/.claude-plugin/plugin.json +11 -0
  85. package/plugins/qa-changes/.codex-plugin/plugin.json +11 -0
  86. package/plugins/qa-changes/skills/github-pr-review/.claude-plugin/plugin.json +18 -0
  87. package/plugins/qa-changes/skills/github-pr-review/.codex-plugin/plugin.json +18 -0
  88. package/plugins/qa-changes/skills/github-pr-review/.plugin/plugin.json +18 -0
  89. package/plugins/qa-changes/skills/github-pr-review/README.md +145 -0
  90. package/plugins/qa-changes/skills/github-pr-review/SKILL.md +187 -0
  91. package/plugins/qa-changes/skills/github-pr-review/commands/github-pr-review.md +8 -0
  92. package/plugins/qa-changes/skills/github-pr-review/references/windows.md +47 -0
  93. package/plugins/qa-changes/skills/qa-changes/README.md +18 -0
  94. package/plugins/qa-changes/skills/qa-changes/SKILL.md +229 -0
  95. package/plugins/qa-changes/skills/qa-changes/commands/qa-changes.md +8 -0
  96. package/plugins/release-notes/.claude-plugin/plugin.json +19 -0
  97. package/plugins/release-notes/.codex-plugin/plugin.json +19 -0
  98. package/plugins/release-notes/skills/release-notes/README.md +24 -0
  99. package/plugins/release-notes/skills/release-notes/SKILL.md +19 -0
  100. package/plugins/release-notes/skills/release-notes/commands/release-notes.md +8 -0
  101. package/plugins/vulnerability-remediation/.claude-plugin/plugin.json +19 -0
  102. package/plugins/vulnerability-remediation/.codex-plugin/plugin.json +19 -0
  103. package/plugins/vulnerability-remediation/skills/github/.claude-plugin/plugin.json +19 -0
  104. package/plugins/vulnerability-remediation/skills/github/.codex-plugin/plugin.json +19 -0
  105. package/plugins/vulnerability-remediation/skills/github/.plugin/plugin.json +19 -0
  106. package/plugins/vulnerability-remediation/skills/github/README.md +42 -0
  107. package/plugins/vulnerability-remediation/skills/github/SKILL.md +107 -0
  108. package/plugins/vulnerability-remediation/skills/github/references/windows.md +48 -0
  109. package/plugins/vulnerability-remediation/skills/github/scripts/agent_conversation.py +143 -0
  110. package/plugins/vulnerability-remediation/skills/github/scripts/github_client.py +230 -0
  111. package/plugins/vulnerability-remediation/skills/security/.claude-plugin/plugin.json +18 -0
  112. package/plugins/vulnerability-remediation/skills/security/.codex-plugin/plugin.json +18 -0
  113. package/plugins/vulnerability-remediation/skills/security/.plugin/plugin.json +18 -0
  114. package/plugins/vulnerability-remediation/skills/security/README.md +38 -0
  115. package/plugins/vulnerability-remediation/skills/security/SKILL.md +33 -0
  116. package/pyproject.toml +2 -2
  117. package/python/openhands_extensions/_version.py +1 -1
  118. package/skills/add-javadoc/.claude-plugin/plugin.json +18 -0
  119. package/skills/add-javadoc/.codex-plugin/plugin.json +18 -0
  120. package/skills/add-skill/.claude-plugin/plugin.json +18 -0
  121. package/skills/add-skill/.codex-plugin/plugin.json +18 -0
  122. package/skills/agent-canvas-environment/.claude-plugin/plugin.json +19 -0
  123. package/skills/agent-canvas-environment/.codex-plugin/plugin.json +19 -0
  124. package/skills/agent-creator/.claude-plugin/plugin.json +20 -0
  125. package/skills/agent-creator/.codex-plugin/plugin.json +20 -0
  126. package/skills/agent-memory/.claude-plugin/plugin.json +18 -0
  127. package/skills/agent-memory/.codex-plugin/plugin.json +18 -0
  128. package/skills/agent-sdk-builder/.claude-plugin/plugin.json +18 -0
  129. package/skills/agent-sdk-builder/.codex-plugin/plugin.json +18 -0
  130. package/skills/azure-devops/.claude-plugin/plugin.json +18 -0
  131. package/skills/azure-devops/.codex-plugin/plugin.json +18 -0
  132. package/skills/bitbucket/.claude-plugin/plugin.json +17 -0
  133. package/skills/bitbucket/.codex-plugin/plugin.json +17 -0
  134. package/skills/bitbucket-cloud/.claude-plugin/plugin.json +18 -0
  135. package/skills/bitbucket-cloud/.codex-plugin/plugin.json +18 -0
  136. package/skills/bitbucket-data-center/.claude-plugin/plugin.json +19 -0
  137. package/skills/bitbucket-data-center/.codex-plugin/plugin.json +19 -0
  138. package/skills/code-review/.claude-plugin/plugin.json +19 -0
  139. package/skills/code-review/.codex-plugin/plugin.json +19 -0
  140. package/skills/code-simplifier/.claude-plugin/plugin.json +21 -0
  141. package/skills/code-simplifier/.codex-plugin/plugin.json +21 -0
  142. package/skills/datadog/.claude-plugin/plugin.json +19 -0
  143. package/skills/datadog/.codex-plugin/plugin.json +19 -0
  144. package/skills/deno/.claude-plugin/plugin.json +18 -0
  145. package/skills/deno/.codex-plugin/plugin.json +18 -0
  146. package/skills/discord/.claude-plugin/plugin.json +18 -0
  147. package/skills/discord/.codex-plugin/plugin.json +18 -0
  148. package/skills/docker/.claude-plugin/plugin.json +17 -0
  149. package/skills/docker/.codex-plugin/plugin.json +17 -0
  150. package/skills/evidence-based-citations/.claude-plugin/plugin.json +20 -0
  151. package/skills/evidence-based-citations/.codex-plugin/plugin.json +20 -0
  152. package/skills/flarglebargle/.claude-plugin/plugin.json +16 -0
  153. package/skills/flarglebargle/.codex-plugin/plugin.json +16 -0
  154. package/skills/frontend-design/.claude-plugin/plugin.json +21 -0
  155. package/skills/frontend-design/.codex-plugin/plugin.json +21 -0
  156. package/skills/github/.claude-plugin/plugin.json +19 -0
  157. package/skills/github/.codex-plugin/plugin.json +19 -0
  158. package/skills/github/scripts/agent_conversation.py +143 -0
  159. package/skills/github/scripts/github_client.py +230 -0
  160. package/skills/github-actions/.claude-plugin/plugin.json +19 -0
  161. package/skills/github-actions/.codex-plugin/plugin.json +19 -0
  162. package/skills/github-agents-md-maintainer/.claude-plugin/plugin.json +19 -0
  163. package/skills/github-agents-md-maintainer/.codex-plugin/plugin.json +19 -0
  164. package/skills/github-agents-md-maintainer/SKILL.md +7 -1
  165. package/skills/github-agents-md-maintainer/scripts/github_client.py +230 -0
  166. package/skills/github-agents-md-maintainer/scripts/main.py +4 -40
  167. package/skills/github-delivery-watchdog/.claude-plugin/plugin.json +9 -0
  168. package/skills/github-delivery-watchdog/.codex-plugin/plugin.json +9 -0
  169. package/skills/github-delivery-watchdog/.plugin/plugin.json +9 -0
  170. package/skills/github-delivery-watchdog/README.md +10 -0
  171. package/skills/github-delivery-watchdog/SKILL.md +35 -0
  172. package/skills/github-delivery-watchdog/commands/github-delivery-watchdog.md +8 -0
  173. package/skills/github-delivery-watchdog/scripts/github_client.py +230 -0
  174. package/skills/github-delivery-watchdog/scripts/worker.py +96 -0
  175. package/skills/github-issue-to-pr/.claude-plugin/plugin.json +19 -0
  176. package/skills/github-issue-to-pr/.codex-plugin/plugin.json +19 -0
  177. package/skills/github-issue-to-pr/SKILL.md +15 -1
  178. package/skills/github-issue-to-pr/scripts/agent_conversation.py +143 -0
  179. package/skills/github-issue-to-pr/scripts/github_client.py +230 -0
  180. package/skills/github-issue-to-pr/scripts/main.py +19 -50
  181. package/skills/github-issue-to-pr/scripts/worker.py +172 -0
  182. package/skills/github-issue-triage/.claude-plugin/plugin.json +9 -0
  183. package/skills/github-issue-triage/.codex-plugin/plugin.json +9 -0
  184. package/skills/github-issue-triage/.plugin/plugin.json +9 -0
  185. package/skills/github-issue-triage/README.md +9 -0
  186. package/skills/github-issue-triage/SKILL.md +34 -0
  187. package/skills/github-issue-triage/commands/github-issue-triage.md +8 -0
  188. package/skills/github-issue-triage/scripts/agent_conversation.py +143 -0
  189. package/skills/github-issue-triage/scripts/github_client.py +230 -0
  190. package/skills/github-issue-triage/scripts/worker.py +106 -0
  191. package/skills/github-pr-review/.claude-plugin/plugin.json +18 -0
  192. package/skills/github-pr-review/.codex-plugin/plugin.json +18 -0
  193. package/skills/github-pr-reviewer/.claude-plugin/plugin.json +20 -0
  194. package/skills/github-pr-reviewer/.codex-plugin/plugin.json +20 -0
  195. package/skills/github-pr-reviewer/SKILL.md +15 -1
  196. package/skills/github-pr-reviewer/scripts/agent_conversation.py +143 -0
  197. package/skills/github-pr-reviewer/scripts/github_client.py +230 -0
  198. package/skills/github-pr-reviewer/scripts/main.py +23 -49
  199. package/skills/github-pr-reviewer/scripts/worker.py +94 -0
  200. package/skills/github-repo-monitor/.claude-plugin/plugin.json +22 -0
  201. package/skills/github-repo-monitor/.codex-plugin/plugin.json +22 -0
  202. package/skills/github-repo-monitor/SKILL.md +7 -1
  203. package/skills/github-repo-monitor/scripts/github_client.py +230 -0
  204. package/skills/github-repo-monitor/scripts/main.py +4 -46
  205. package/skills/gitlab/.claude-plugin/plugin.json +17 -0
  206. package/skills/gitlab/.codex-plugin/plugin.json +17 -0
  207. package/skills/gitlab-issue-to-mr/.claude-plugin/plugin.json +19 -0
  208. package/skills/gitlab-issue-to-mr/.codex-plugin/plugin.json +19 -0
  209. package/skills/gitlab-issue-to-mr/.plugin/plugin.json +19 -0
  210. package/skills/gitlab-issue-to-mr/README.md +92 -0
  211. package/skills/gitlab-issue-to-mr/SKILL.md +408 -0
  212. package/skills/gitlab-issue-to-mr/commands/issue-to-mr-setup.md +8 -0
  213. package/skills/gitlab-issue-to-mr/references/state-schema.md +140 -0
  214. package/skills/gitlab-issue-to-mr/scripts/main.py +1448 -0
  215. package/skills/incident-retrospective/.claude-plugin/plugin.json +21 -0
  216. package/skills/incident-retrospective/.codex-plugin/plugin.json +21 -0
  217. package/skills/index.js +52 -6
  218. package/skills/iterate/.claude-plugin/plugin.json +13 -0
  219. package/skills/iterate/.codex-plugin/plugin.json +13 -0
  220. package/skills/jira-issue-to-pr/.claude-plugin/plugin.json +19 -0
  221. package/skills/jira-issue-to-pr/.codex-plugin/plugin.json +19 -0
  222. package/skills/jupyter/.claude-plugin/plugin.json +18 -0
  223. package/skills/jupyter/.codex-plugin/plugin.json +18 -0
  224. package/skills/kubernetes/.claude-plugin/plugin.json +18 -0
  225. package/skills/kubernetes/.codex-plugin/plugin.json +18 -0
  226. package/skills/learn-from-code-review/.claude-plugin/plugin.json +19 -0
  227. package/skills/learn-from-code-review/.codex-plugin/plugin.json +19 -0
  228. package/skills/linear/.claude-plugin/plugin.json +19 -0
  229. package/skills/linear/.codex-plugin/plugin.json +19 -0
  230. package/skills/linear-triage/.claude-plugin/plugin.json +21 -0
  231. package/skills/linear-triage/.codex-plugin/plugin.json +21 -0
  232. package/skills/news-digest/.claude-plugin/plugin.json +19 -0
  233. package/skills/news-digest/.codex-plugin/plugin.json +19 -0
  234. package/skills/notion/.claude-plugin/plugin.json +17 -0
  235. package/skills/notion/.codex-plugin/plugin.json +17 -0
  236. package/skills/npm/.claude-plugin/plugin.json +17 -0
  237. package/skills/npm/.codex-plugin/plugin.json +17 -0
  238. package/skills/openhands-api/.claude-plugin/plugin.json +22 -0
  239. package/skills/openhands-api/.codex-plugin/plugin.json +22 -0
  240. package/skills/openhands-automation/.claude-plugin/plugin.json +19 -0
  241. package/skills/openhands-automation/.codex-plugin/plugin.json +19 -0
  242. package/skills/openhands-automation/README.md +1 -1
  243. package/skills/openhands-automation/SKILL.md +18 -8
  244. package/skills/openhands-enterprise-troubleshooting/.claude-plugin/plugin.json +20 -0
  245. package/skills/openhands-enterprise-troubleshooting/.codex-plugin/plugin.json +20 -0
  246. package/skills/openhands-enterprise-troubleshooting/.plugin/plugin.json +20 -0
  247. package/skills/openhands-enterprise-troubleshooting/README.md +79 -0
  248. package/skills/openhands-enterprise-troubleshooting/SKILL.md +339 -0
  249. package/skills/openhands-enterprise-troubleshooting/references/diagnostics.md +698 -0
  250. package/skills/openhands-enterprise-troubleshooting/references/support-bundle-analysis.md +570 -0
  251. package/skills/openhands-enterprise-troubleshooting/scripts/bundle_triage.py +532 -0
  252. package/skills/openhands-sdk/.claude-plugin/plugin.json +20 -0
  253. package/skills/openhands-sdk/.codex-plugin/plugin.json +20 -0
  254. package/skills/openhands-sdk/SKILL.md +2 -0
  255. package/skills/pdflatex/.claude-plugin/plugin.json +18 -0
  256. package/skills/pdflatex/.codex-plugin/plugin.json +18 -0
  257. package/skills/plain-english-content/.claude-plugin/plugin.json +15 -0
  258. package/skills/plain-english-content/.codex-plugin/plugin.json +15 -0
  259. package/skills/prd/.claude-plugin/plugin.json +19 -0
  260. package/skills/prd/.codex-plugin/plugin.json +19 -0
  261. package/skills/research-brief/.claude-plugin/plugin.json +20 -0
  262. package/skills/research-brief/.codex-plugin/plugin.json +20 -0
  263. package/skills/security/.claude-plugin/plugin.json +18 -0
  264. package/skills/security/.codex-plugin/plugin.json +18 -0
  265. package/skills/skill-creator/.claude-plugin/plugin.json +17 -0
  266. package/skills/skill-creator/.codex-plugin/plugin.json +17 -0
  267. package/skills/slack-channel-monitor/.claude-plugin/plugin.json +21 -0
  268. package/skills/slack-channel-monitor/.codex-plugin/plugin.json +21 -0
  269. package/skills/slack-standup-digest/.claude-plugin/plugin.json +21 -0
  270. package/skills/slack-standup-digest/.codex-plugin/plugin.json +21 -0
  271. package/skills/spark-version-upgrade/.claude-plugin/plugin.json +20 -0
  272. package/skills/spark-version-upgrade/.codex-plugin/plugin.json +20 -0
  273. package/skills/ssh/.claude-plugin/plugin.json +18 -0
  274. package/skills/ssh/.codex-plugin/plugin.json +18 -0
  275. package/skills/swift-linux/.claude-plugin/plugin.json +17 -0
  276. package/skills/swift-linux/.codex-plugin/plugin.json +17 -0
  277. package/skills/technical-writing/.claude-plugin/plugin.json +15 -0
  278. package/skills/technical-writing/.codex-plugin/plugin.json +15 -0
  279. package/skills/theme-factory/.claude-plugin/plugin.json +19 -0
  280. package/skills/theme-factory/.codex-plugin/plugin.json +19 -0
  281. package/skills/ticket-to-code-change/.claude-plugin/plugin.json +21 -0
  282. package/skills/ticket-to-code-change/.codex-plugin/plugin.json +21 -0
  283. package/skills/upstream-fork-sync/.claude-plugin/plugin.json +21 -0
  284. package/skills/upstream-fork-sync/.codex-plugin/plugin.json +21 -0
  285. package/skills/uv/.claude-plugin/plugin.json +18 -0
  286. package/skills/uv/.codex-plugin/plugin.json +18 -0
  287. package/skills/vercel/.claude-plugin/plugin.json +18 -0
  288. package/skills/vercel/.codex-plugin/plugin.json +18 -0
  289. package/tests/fixtures/automations/capabilities.json +6 -3
  290. package/tests/fixtures/automations/github-pr-reviewer.json +64 -43
  291. package/tests/github_automation_helpers.py +31 -0
  292. package/tests/test_agent_conversation_dispatch.py +180 -0
  293. package/tests/test_automation_setup.py +3 -3
  294. package/tests/test_github_automation_foundation.py +73 -0
  295. package/tests/test_github_developer_delivery.py +150 -0
  296. package/tests/test_github_reviewer_delivery.py +110 -0
  297. package/tests/test_github_skill_installation.py +63 -0
  298. package/tests/test_github_triage_delivery.py +90 -0
  299. package/tests/test_github_watchdog_delivery.py +233 -0
  300. package/tests/test_gitlab_issue_to_mr.py +823 -0
  301. package/.pr/custom-automation-event-trigger.png +0 -0
  302. package/.pr/custom-automation-plugin-fields.png +0 -0
  303. package/.pr/custom-automation-prompt-review.png +0 -0
  304. package/.pr/custom-automation-prompt-scheduled.png +0 -0
  305. package/.pr/custom-automation-upload-fields.png +0 -0
@@ -8,10 +8,10 @@ GitHub `labeled` event has not already been processed by this automation.
8
8
  Each repository is polled independently and keeps its own state document, so
9
9
  pull-request numbers never collide across repositories.
10
10
 
11
- The script owns the repository checkout: it downloads the pull request's head
12
- commit as a tarball, hands the agent that directory as its workspace, and
13
- removes it once the review has finished. The agent never clones, checks out, or
14
- deletes anything.
11
+ This standalone script owns the repository checkout: it downloads the pull
12
+ request's head commit as a tarball, hands the agent that directory as its
13
+ workspace, and removes it once the review has finished. Catalog workers may
14
+ instead reuse its prompt builder with their own workspace instructions.
15
15
  """
16
16
 
17
17
  import io
@@ -26,7 +26,9 @@ import urllib.error
26
26
  import urllib.request
27
27
  from collections.abc import Callable
28
28
  from pathlib import Path, PurePosixPath
29
- from urllib.parse import urlencode
29
+
30
+ from github_client import github_request as _github_request
31
+ from github_client import github_paginate as _github_paginate
30
32
 
31
33
  # Configuration. Two setup paths write it, and both end up here:
32
34
  #
@@ -336,46 +338,6 @@ def save_state(repo: str, state: dict) -> None:
336
338
  print(f" State saved to {path}")
337
339
 
338
340
 
339
- def _github_request(
340
- token: str,
341
- method: str,
342
- path: str,
343
- params: dict | None = None,
344
- body: dict | None = None,
345
- accept: str = "application/vnd.github+json",
346
- ) -> tuple:
347
- url = f"https://api.github.com{path}"
348
- if params:
349
- url = f"{url}?{urlencode(params)}"
350
- headers = {
351
- "Authorization": f"Bearer {token}",
352
- "Accept": accept,
353
- "X-GitHub-Api-Version": "2022-11-28",
354
- "Content-Type": "application/json",
355
- }
356
- data = json.dumps(body).encode() if body is not None else None
357
- req = urllib.request.Request(url, data=data, headers=headers, method=method)
358
- with urllib.request.urlopen(req) as r:
359
- raw = r.read()
360
- return (json.loads(raw) if raw.strip() else {}), dict(r.headers)
361
-
362
-
363
- def _github_paginate(token: str, path: str, params: dict | None = None) -> list:
364
- results = []
365
- page = 1
366
- base_params = dict(params or {})
367
- base_params.setdefault("per_page", 100)
368
- while True:
369
- base_params["page"] = page
370
- data, _ = _github_request(token, "GET", path, params=base_params)
371
- if not isinstance(data, list):
372
- break
373
- results.extend(data)
374
- if len(data) < base_params["per_page"]:
375
- break
376
- page += 1
377
- return results
378
-
379
341
 
380
342
  def _resolve_github_token() -> str:
381
343
  try:
@@ -770,7 +732,16 @@ def _load_repo_review_guide(workspace_dir: Path) -> str | None:
770
732
  return None
771
733
 
772
734
 
773
- def _build_review_prompt(repo: str, pr: dict, head_sha: str, label_event: dict, repo_review_guide: str | None = None) -> str:
735
+ def _build_review_prompt(
736
+ repo: str,
737
+ pr: dict,
738
+ head_sha: str,
739
+ label_event: dict,
740
+ repo_review_guide: str | None = None,
741
+ *,
742
+ workspace_instructions: str | None = None,
743
+ github_token_secret: str = "GITHUB_PERSONAL_ACCESS_TOKEN",
744
+ ) -> str:
774
745
  number = pr.get("number", "?")
775
746
  title = pr.get("title", "(no title)")
776
747
  body = (pr.get("body") or "").strip() or "(no description)"
@@ -790,6 +761,10 @@ def _build_review_prompt(repo: str, pr: dict, head_sha: str, label_event: dict,
790
761
  f"\n\nRepo-specific review guide (from {REPO_REVIEW_GUIDE_PATH}):\n---\n{repo_review_guide}\n---\n"
791
762
  if repo_review_guide else ""
792
763
  )
764
+ workspace = workspace_instructions or (
765
+ "The workspace is already the repository root at the exact Head SHA above. "
766
+ "Do not clone, fetch, check out, or delete the repository."
767
+ )
793
768
 
794
769
  return (
795
770
  "You are an AI code reviewer. Review the GitHub pull request below and publish "
@@ -806,8 +781,7 @@ def _build_review_prompt(repo: str, pr: dict, head_sha: str, label_event: dict,
806
781
  f"URL : {html_url}\n"
807
782
  f"\nPR Description:\n---\n{body}\n---\n\n"
808
783
  "Required workflow:\n"
809
- "1. The workspace is already the repository root at the exact Head SHA above. "
810
- "Do not clone, fetch, check out, or delete the repository.\n"
784
+ f"1. {workspace}\n"
811
785
  "2. Before reviewing, you MUST read the repository's own guidance to understand the repo first.\n"
812
786
  " Read `AGENTS.md` at the repository root (and any nested `AGENTS.md` covering the "
813
787
  "changed files), plus other relevant docs when present - e.g. `CONTRIBUTING.md`, "
@@ -815,7 +789,7 @@ def _build_review_prompt(repo: str, pr: dict, head_sha: str, label_event: dict,
815
789
  "guidance to your review.\n"
816
790
  " Then inspect the PR discussion, existing review comments, changed files, and the diff, "
817
791
  "together with the surrounding code in the workspace.\n"
818
- " Use `gh` or GitHub REST API calls with `GITHUB_PERSONAL_ACCESS_TOKEN`; never print secret values.\n"
792
+ f" Use `gh` or GitHub REST API calls with `{github_token_secret}`; never print secret values.\n"
819
793
  "3. Ground every finding in the workspace code. Before using an inline location, verify that "
820
794
  "the path and line are part of this pull request's diff.\n"
821
795
  f"4. Publish one review with `POST /repos/{repo}/pulls/{number}/reviews`, using "
@@ -0,0 +1,94 @@
1
+ """Select labeled PR heads and delegate each review to a sandboxed agent."""
2
+
3
+ import json
4
+
5
+ import main as workflow
6
+ from agent_conversation import AgentConversationDispatcher
7
+ from github_client import GitHubRepository, run_repositories
8
+
9
+
10
+ class PullRequestReviewer(GitHubRepository):
11
+ name = "github-pr-reviewer"
12
+
13
+ def _prompt(self, pr, label_event):
14
+ number = pr["number"]
15
+ sha = pr["head"]["sha"]
16
+ label = self.config.get("trigger_label", workflow.TRIGGER_LABEL)
17
+ token = self.token_name
18
+ workspace = (
19
+ "The workspace contains an empty Git repository. Before fetching, run "
20
+ f"`GH_TOKEN=${{{token}}} gh auth setup-git` so Git uses the "
21
+ "profile-scoped credential without storing it in the remote URL. Set "
22
+ f"the plain HTTPS origin to `https://github.com/{self.repository}.git`, "
23
+ f"fetch PR #{number}, and check out exact head `{sha}` in detached-HEAD "
24
+ "mode. Set `GIT_TERMINAL_PROMPT=0` on Git network commands so a missing "
25
+ "permission fails immediately instead of waiting for input."
26
+ )
27
+ prompt = workflow._build_review_prompt(
28
+ self.repository,
29
+ pr,
30
+ sha,
31
+ label_event,
32
+ workspace_instructions=workspace,
33
+ github_token_secret=token,
34
+ )
35
+ return (
36
+ prompt + "\n\nAcceptance reporting:\n"
37
+ "- Inspect the current GitHub Actions results for the exact head and run "
38
+ "the repository's appropriate focused tests in the workspace. Do not "
39
+ "modify tracked files.\n"
40
+ f"- Re-read {self.repository} PR #{number} immediately before reporting. "
41
+ f"If its head is no longer `{sha}`, publish no status and leave `{label}` "
42
+ "in place so the new head is reviewed.\n"
43
+ "- After the readable native review is accepted by GitHub, set commit "
44
+ "status `software-factory/review` to success only for an `✅ APPROVED` "
45
+ "verdict, otherwise failure. Set `software-factory/tests` to success only "
46
+ "when the relevant checks and tests pass, otherwise failure. Use the exact "
47
+ f"head `{sha}` for both statuses.\n"
48
+ f"- After both statuses are visible on that head, remove the `{label}` "
49
+ "label. Never paste JSON artifacts or full command logs into comments."
50
+ )
51
+
52
+ def run(self):
53
+ repository_id = self.gh("GET", "")["id"]
54
+ label = self.config.get("trigger_label", workflow.TRIGGER_LABEL)
55
+ prs = self.gh_pages("/pulls?state=open&sort=updated&direction=asc")
56
+ for candidate in prs:
57
+ if label not in {item["name"] for item in candidate.get("labels", [])}:
58
+ continue
59
+ try:
60
+ pr = self.gh("GET", f"/pulls/{candidate['number']}")
61
+ event = workflow._latest_trigger_label_event(
62
+ self.token, self.repository, pr["number"]
63
+ )
64
+ if event is None:
65
+ continue
66
+ sha = pr["head"]["sha"]
67
+ result = self.dispatcher.deliver(
68
+ subject=f"{repository_id}:pr:{pr['number']}",
69
+ delivery=f"{event['id']}:{sha}",
70
+ prompt=self._prompt(pr, event),
71
+ )
72
+ print(
73
+ json.dumps(
74
+ {
75
+ "repository": self.repository,
76
+ "pr": pr["number"],
77
+ "head_sha": sha,
78
+ "disposition": result["disposition"],
79
+ "conversation_id": result["conversation_id"],
80
+ }
81
+ ),
82
+ flush=True,
83
+ )
84
+ except Exception as exc: # noqa: BLE001 - one PR must not block the scan
85
+ print(
86
+ f"Failed to submit {self.repository} PR "
87
+ f"#{candidate.get('number', '?')}: {exc}",
88
+ flush=True,
89
+ )
90
+
91
+
92
+ if __name__ == "__main__":
93
+ with AgentConversationDispatcher() as dispatcher:
94
+ run_repositories(PullRequestReviewer, dispatcher=dispatcher)
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "github-repo-monitor",
3
+ "version": "1.0.0",
4
+ "description": "Create a cron automation that polls a GitHub repository for issue and PR comments containing a configurable trigger phrase (@OpenHands by default). Starts an OpenHands conversation with full issue/PR context, posts acknowledgement comments with a conversation link, and summarises results back to the issue/PR when the agent finishes.",
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
+ "github",
14
+ "monitor",
15
+ "issues",
16
+ "pull-requests",
17
+ "trigger",
18
+ "cron",
19
+ "automation",
20
+ "integration"
21
+ ]
22
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "github-repo-monitor",
3
+ "version": "1.0.0",
4
+ "description": "Create a cron automation that polls a GitHub repository for issue and PR comments containing a configurable trigger phrase (@OpenHands by default). Starts an OpenHands conversation with full issue/PR context, posts acknowledgement comments with a conversation link, and summarises results back to the issue/PR when the agent finishes.",
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
+ "github",
14
+ "monitor",
15
+ "issues",
16
+ "pull-requests",
17
+ "trigger",
18
+ "cron",
19
+ "automation",
20
+ "integration"
21
+ ]
22
+ }
@@ -37,6 +37,10 @@ On every subsequent run:
37
37
 
38
38
  ---
39
39
 
40
+ The script imports shared GitHub transport from
41
+ `scripts/github_client.py`, installed with this skill. Include it beside
42
+ `main.py` when packaging manually, as shown below.
43
+
40
44
  ## Prerequisites
41
45
 
42
46
  ### Required secret
@@ -181,9 +185,11 @@ constant substitutions near the top of the file:
181
185
  | `ALLOWED_GITHUB_LOGINS = ["<TOKEN_OWNER>"]` | `ALLOWED_GITHUB_LOGINS = {allowed_logins_list}` |
182
186
  | `DEFAULT_OPENHANDS_URL = "http://localhost:8000"` | `DEFAULT_OPENHANDS_URL = "{url}"` (keep default if the user has no preference) |
183
187
 
184
- Write the customised script to a temporary build directory:
188
+ Run these commands from this skill's directory and write the customised script
189
+ to a temporary build directory:
185
190
  ```bash
186
191
  mkdir -p /tmp/github-monitor-build
192
+ cp -L scripts/github_client.py /tmp/github-monitor-build/github_client.py
187
193
  # (write the customised main.py to /tmp/github-monitor-build/main.py)
188
194
  ```
189
195
 
@@ -0,0 +1,230 @@
1
+ """Shared GitHub transport and repository operations for GitHub automations."""
2
+
3
+ import argparse
4
+ import json
5
+ import os
6
+ import re
7
+ import subprocess
8
+ from functools import cached_property
9
+ from pathlib import Path
10
+ from urllib.error import HTTPError
11
+ from urllib.parse import parse_qsl, urlencode, urlsplit
12
+ from urllib.request import Request, urlopen
13
+
14
+
15
+ def _load_secret(name: str) -> str:
16
+ """Read one named secret from the environment or configured Agent Server."""
17
+ value = os.environ.get(name)
18
+ if value:
19
+ return value
20
+
21
+ from openhands.sdk.workspace import RemoteWorkspace
22
+
23
+ workspace = RemoteWorkspace(
24
+ host=os.environ["AGENT_SERVER_URL"],
25
+ api_key=os.environ["SESSION_API_KEY"],
26
+ working_dir=os.environ.get("WORKSPACE_BASE", "/workspace"),
27
+ )
28
+ try:
29
+ secret = workspace.get_secrets([name]).get(name)
30
+ value = secret.get_value() if secret else None
31
+ finally:
32
+ workspace.reset_client()
33
+ if not value:
34
+ raise ValueError(f"The GitHub credential {name} is unavailable")
35
+ return value
36
+
37
+
38
+ def github_request(
39
+ token: str,
40
+ method: str,
41
+ path: str,
42
+ params: dict | None = None,
43
+ body: dict | None = None,
44
+ accept: str = "application/vnd.github+json",
45
+ ) -> tuple:
46
+ url = f"https://api.github.com{path}"
47
+ if params:
48
+ url = f"{url}?{urlencode(params)}"
49
+ headers = {
50
+ "Authorization": f"Bearer {token}",
51
+ "Accept": accept,
52
+ "X-GitHub-Api-Version": "2022-11-28",
53
+ "Content-Type": "application/json",
54
+ }
55
+ data = json.dumps(body).encode() if body is not None else None
56
+ req = Request(url, data=data, headers=headers, method=method)
57
+ with urlopen(req, timeout=90) as r:
58
+ raw = r.read()
59
+ return (json.loads(raw) if raw.strip() else {}), dict(r.headers)
60
+
61
+
62
+ def github_paginate(token: str, path: str, params: dict | None = None) -> list:
63
+ results = []
64
+ base_params = dict(params or {})
65
+ base_params.setdefault("per_page", 100)
66
+ for page in range(1, 101):
67
+ base_params["page"] = page
68
+ data, _ = github_request(token, "GET", path, params=base_params)
69
+ if not isinstance(data, list):
70
+ raise TypeError("Expected a paginated GitHub list")
71
+ results.extend(data)
72
+ if len(data) < int(base_params["per_page"]):
73
+ return results
74
+ raise RuntimeError("GitHub pagination exceeded limit")
75
+
76
+
77
+ class GitHubRepository:
78
+ name = "GitHub automation"
79
+
80
+ def __init__(
81
+ self,
82
+ config_path=Path("config.json"),
83
+ *,
84
+ github_token_secret,
85
+ repository=None,
86
+ conversation=None,
87
+ dispatcher=None,
88
+ ):
89
+ self.config = json.loads(Path(config_path).read_text())
90
+ self.repository = repository or self.config["repository"]
91
+ if not re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", self.repository):
92
+ raise ValueError("repository must be owner/repo")
93
+ if not re.fullmatch(r"[A-Z_][A-Z0-9_]*", github_token_secret):
94
+ raise ValueError(
95
+ "Expected the environment variable containing the GitHub token"
96
+ )
97
+ self.token_name = github_token_secret
98
+ self.token = _load_secret(github_token_secret)
99
+ self.conversation = conversation
100
+ self.conversation_id = str(conversation.id) if conversation else None
101
+ self.dispatcher = dispatcher
102
+ self.workspace = Path(os.environ["WORKSPACE_BASE"])
103
+ self.project = self.workspace
104
+ self.evidence = self.workspace / "evidence"
105
+ self.evidence.mkdir(exist_ok=True)
106
+ self._completed_dependencies = {}
107
+
108
+ @cached_property
109
+ def base_branch(self):
110
+ return self.config.get("base_branch") or self.gh("GET", "")["default_branch"]
111
+
112
+ @property
113
+ def github_instructions(self):
114
+ return (
115
+ f"Use `GH_TOKEN=${self.token_name} gh api` for GitHub requests. "
116
+ "Never print the credential value. "
117
+ f"Only {self.repository} is in scope. Work in {self.project}. "
118
+ "Do not modify the automation bundle or its configuration."
119
+ )
120
+
121
+ def gh(self, method, path, body=None):
122
+ return github_request(
123
+ self.token, method, f"/repos/{self.repository}" + path, body=body
124
+ )[0]
125
+
126
+ def shell(self, args, cwd=None, timeout=300):
127
+ result = subprocess.run(
128
+ args,
129
+ cwd=cwd or self.project,
130
+ text=True,
131
+ stdout=subprocess.PIPE,
132
+ stderr=subprocess.STDOUT,
133
+ timeout=timeout,
134
+ check=False,
135
+ )
136
+ if result.returncode:
137
+ raise RuntimeError(
138
+ f"{args[0]} failed: {result.stdout[-4000:].replace(self.token, '[REDACTED]')}"
139
+ )
140
+ return result.stdout.strip()
141
+
142
+ def comment(self, number, text):
143
+ return self.gh(
144
+ "POST",
145
+ f"/issues/{number}/comments",
146
+ {
147
+ "body": text
148
+ + f"\n\nFactory role: `{self.name}`; conversation: `{self.conversation_id}`."
149
+ + "\n\n_This comment was posted by an AI agent (OpenHands)._"
150
+ },
151
+ )
152
+
153
+ def open_issues(self):
154
+ return [
155
+ i for i in self.gh_pages("/issues?state=open") if "pull_request" not in i
156
+ ]
157
+
158
+ def statuses(self, sha):
159
+ result = {}
160
+ for item in self.gh_pages(f"/commits/{sha}/statuses"):
161
+ result.setdefault(item["context"], item["state"])
162
+ return result
163
+
164
+ def completed_dependency(self, number):
165
+ if number in self._completed_dependencies:
166
+ return self._completed_dependencies[number]
167
+ try:
168
+ dependency = self.gh("GET", f"/issues/{number}")
169
+ except HTTPError as exc:
170
+ if exc.code == 404:
171
+ return False
172
+ raise
173
+ completed = (
174
+ dependency["state"] == "closed"
175
+ and dependency.get("state_reason") == "completed"
176
+ )
177
+ self._completed_dependencies[number] = completed
178
+ return completed
179
+
180
+ def dependencies_complete(self, issue):
181
+ """Honor explicit Depends on lines; unknown/incomplete issues remain blocked."""
182
+ for line in re.findall(
183
+ "^Depends on:\\s*(.+)$",
184
+ issue.get("body") or "",
185
+ re.MULTILINE | re.IGNORECASE,
186
+ ):
187
+ for number in re.findall("#(\\d+)", line):
188
+ if not self.completed_dependency(number):
189
+ return False
190
+ return True
191
+
192
+ def gh_pages(self, endpoint):
193
+ split = urlsplit(endpoint)
194
+ return github_paginate(
195
+ self.token,
196
+ f"/repos/{self.repository}" + split.path,
197
+ params=dict(parse_qsl(split.query)),
198
+ )
199
+
200
+
201
+ def run_repositories(automation_type, conversation=None, dispatcher=None):
202
+ parser = argparse.ArgumentParser(description=automation_type.__doc__)
203
+ parser.add_argument("--github-token-secret")
204
+ args = parser.parse_args()
205
+ config = json.loads(Path("config.json").read_text())
206
+ token_name = args.github_token_secret or config.get(
207
+ "github_token_secret", "GITHUB_PERSONAL_ACCESS_TOKEN"
208
+ )
209
+ repositories = config.get("repos") or [config["repository"]]
210
+ failures = []
211
+ for repository in repositories:
212
+ options = dict(
213
+ github_token_secret=token_name,
214
+ repository=repository,
215
+ conversation=conversation,
216
+ )
217
+ if dispatcher is not None:
218
+ options["dispatcher"] = dispatcher
219
+ automation = automation_type(**options)
220
+ try:
221
+ automation.run()
222
+ except Exception as exc: # noqa: BLE001 - one repository must not block others
223
+ failures.append(repository)
224
+ print(
225
+ json.dumps({"repository": repository, "error": type(exc).__name__}),
226
+ flush=True,
227
+ )
228
+ if failures:
229
+ raise RuntimeError("Automation failed for: " + ", ".join(failures))
230
+ return str(conversation.id) if conversation else None
@@ -34,7 +34,10 @@ import time
34
34
  import urllib.error
35
35
  import urllib.request
36
36
  from datetime import datetime, timedelta, timezone
37
- from urllib.parse import urlencode
37
+
38
+ from github_client import github_request as _github_request
39
+ from github_client import github_paginate as _github_paginate
40
+
38
41
 
39
42
  # ── Embedded configuration (filled in by the skill at creation time) ──────────
40
43
  REPO = "owner/repo" # e.g. "microsoft/vscode"
@@ -210,51 +213,6 @@ def save_state(state: dict) -> None:
210
213
 
211
214
  # ── GitHub API helpers ─────────────────────────────────────────────────────────
212
215
 
213
- def _github_request(
214
- token: str,
215
- method: str,
216
- path: str,
217
- params: dict | None = None,
218
- body: dict | None = None,
219
- ) -> tuple[dict | list, dict]:
220
- """Low-level GitHub API call. Returns (parsed_body, response_headers).
221
- Raises urllib.error.HTTPError on non-2xx responses.
222
- """
223
- base = "https://api.github.com"
224
- url = f"{base}{path}"
225
- if params:
226
- url = f"{url}?{urlencode(params)}"
227
- headers = {
228
- "Authorization": f"Bearer {token}",
229
- "Accept": "application/vnd.github+json",
230
- "X-GitHub-Api-Version": "2022-11-28",
231
- "Content-Type": "application/json",
232
- }
233
- data = json.dumps(body).encode() if body is not None else None
234
- req = urllib.request.Request(url, data=data, headers=headers, method=method)
235
- with urllib.request.urlopen(req) as r:
236
- resp_headers = dict(r.headers)
237
- raw = r.read()
238
- return (json.loads(raw) if raw.strip() else {}), resp_headers
239
-
240
-
241
- def _github_paginate(token: str, path: str, params: dict | None = None) -> list:
242
- """Fetch all pages from a GitHub list endpoint."""
243
- results = []
244
- page = 1
245
- base_params = dict(params or {})
246
- base_params.setdefault("per_page", 100)
247
- while True:
248
- base_params["page"] = page
249
- data, _ = _github_request(token, "GET", path, params=base_params)
250
- if not isinstance(data, list):
251
- break
252
- results.extend(data)
253
- if len(data) < base_params["per_page"]:
254
- break
255
- page += 1
256
- return results
257
-
258
216
 
259
217
  def _resolve_github_token() -> str:
260
218
  """Fetch GITHUB_PERSONAL_ACCESS_TOKEN from secrets. Raises RuntimeError if absent."""
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "gitlab",
3
+ "version": "1.0.0",
4
+ "description": "Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when working with code hosted on GitLab or managing GitLab resources.",
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
+ "gitlab",
14
+ "git",
15
+ "merge-request"
16
+ ]
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "gitlab",
3
+ "version": "1.0.0",
4
+ "description": "Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when working with code hosted on GitLab or managing GitLab resources.",
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
+ "gitlab",
14
+ "git",
15
+ "merge-request"
16
+ ]
17
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "gitlab-issue-to-mr",
3
+ "version": "1.0.0",
4
+ "description": "Create an automation that implements GitLab issues when a configurable trigger label is applied. It clones the default branch, starts one OpenHands conversation per label event, then commits, pushes, and opens the merge request itself, without ever handing the agent a push credential.",
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
+ "gitlab",
14
+ "issue",
15
+ "merge-request",
16
+ "automation",
17
+ "integration"
18
+ ]
19
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "gitlab-issue-to-mr",
3
+ "version": "1.0.0",
4
+ "description": "Create an automation that implements GitLab issues when a configurable trigger label is applied. It clones the default branch, starts one OpenHands conversation per label event, then commits, pushes, and opens the merge request itself, without ever handing the agent a push credential.",
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
+ "gitlab",
14
+ "issue",
15
+ "merge-request",
16
+ "automation",
17
+ "integration"
18
+ ]
19
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "gitlab-issue-to-mr",
3
+ "version": "1.0.0",
4
+ "description": "Create an automation that implements GitLab issues when a configurable trigger label is applied. It clones the default branch, starts one OpenHands conversation per label event, then commits, pushes, and opens the merge request itself, without ever handing the agent a push credential.",
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
+ "gitlab",
14
+ "issue",
15
+ "merge-request",
16
+ "automation",
17
+ "integration"
18
+ ]
19
+ }