@openhands/extensions 0.0.1-alpha → 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,127 @@
1
+ from __future__ import annotations
2
+
3
+ import random
4
+ import time
5
+ from dataclasses import dataclass
6
+ from typing import Any, Mapping
7
+
8
+ import requests
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class DiscordRateLimitInfo:
13
+ retry_after: float
14
+ is_global: bool
15
+ bucket: str | None
16
+ remaining: str | None
17
+ reset_after: str | None
18
+
19
+
20
+ class DiscordHTTPError(RuntimeError):
21
+ pass
22
+
23
+
24
+ def _parse_rate_limit_info(*, status_code: int, headers: Mapping[str, str], json_body: Any) -> DiscordRateLimitInfo | None:
25
+ if status_code != 429:
26
+ return None
27
+
28
+ retry_after: float | None = None
29
+ is_global = False
30
+
31
+ if isinstance(json_body, dict):
32
+ retry_after_val = json_body.get("retry_after")
33
+ if isinstance(retry_after_val, (int, float, str)):
34
+ try:
35
+ retry_after = float(retry_after_val)
36
+ except ValueError:
37
+ retry_after = None
38
+ is_global = bool(json_body.get("global", False))
39
+
40
+ if retry_after is None:
41
+ hdr = headers.get("Retry-After")
42
+ if hdr is not None:
43
+ try:
44
+ retry_after = float(hdr)
45
+ except ValueError:
46
+ retry_after = None
47
+
48
+ if retry_after is None:
49
+ reset_after = headers.get("X-RateLimit-Reset-After")
50
+ if reset_after is not None:
51
+ try:
52
+ retry_after = float(reset_after)
53
+ except ValueError:
54
+ retry_after = None
55
+
56
+ if retry_after is None:
57
+ return None
58
+
59
+ return DiscordRateLimitInfo(
60
+ retry_after=retry_after,
61
+ is_global=is_global,
62
+ bucket=headers.get("X-RateLimit-Bucket"),
63
+ remaining=headers.get("X-RateLimit-Remaining"),
64
+ reset_after=headers.get("X-RateLimit-Reset-After"),
65
+ )
66
+
67
+
68
+ def post_json(
69
+ *,
70
+ url: str,
71
+ headers: Mapping[str, str],
72
+ payload: Mapping[str, object],
73
+ timeout_s: float = 30,
74
+ max_retries: int = 3,
75
+ max_retry_after_s: float = 60.0,
76
+ jitter_s: float = 0.25,
77
+ redact_url_in_errors: bool = False,
78
+ ) -> dict[str, object] | None:
79
+ attempt = 0
80
+ while True:
81
+ attempt += 1
82
+ try:
83
+ resp = requests.post(url, headers=dict(headers), json=dict(payload), timeout=timeout_s)
84
+ except requests.RequestException as e:
85
+ raise DiscordHTTPError(f"HTTP request failed ({e}).") from e
86
+
87
+ body_text = resp.text or ""
88
+ json_body: Any = None
89
+ if body_text:
90
+ try:
91
+ json_body = resp.json()
92
+ except ValueError:
93
+ json_body = None
94
+
95
+ rl = _parse_rate_limit_info(status_code=resp.status_code, headers=resp.headers, json_body=json_body)
96
+ if rl is not None and attempt <= max_retries:
97
+ sleep_s = min(max(0.0, rl.retry_after), max_retry_after_s)
98
+ if jitter_s > 0:
99
+ sleep_s += random.uniform(0.0, jitter_s)
100
+ time.sleep(sleep_s)
101
+ continue
102
+
103
+ if resp.status_code >= 400:
104
+ context_bits: list[str] = []
105
+ if not redact_url_in_errors:
106
+ context_bits.append(f"url={url}")
107
+ if rl is not None:
108
+ context_bits.append(f"rate_limit_global={rl.is_global}")
109
+ if rl.bucket is not None:
110
+ context_bits.append(f"rate_limit_bucket={rl.bucket}")
111
+ if rl.remaining is not None:
112
+ context_bits.append(f"rate_limit_remaining={rl.remaining}")
113
+ if rl.reset_after is not None:
114
+ context_bits.append(f"rate_limit_reset_after={rl.reset_after}")
115
+
116
+ context = (" " + " ".join(context_bits)) if context_bits else ""
117
+
118
+ msg = f"HTTP request failed (HTTP {resp.status_code}).{context}"
119
+ if body_text:
120
+ msg += f" Response: {body_text[:500]}"
121
+ raise DiscordHTTPError(msg)
122
+
123
+ if not body_text:
124
+ return None
125
+ if isinstance(json_body, dict):
126
+ return json_body
127
+ return {"raw": body_text}
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import os
8
+ import sys
9
+ import urllib.parse
10
+ import urllib.request
11
+
12
+ from ._http import DiscordHTTPError, post_json
13
+
14
+
15
+ def _with_wait_param(url: str, *, wait: bool) -> str:
16
+ if not wait:
17
+ return url
18
+
19
+ parts = urllib.parse.urlsplit(url)
20
+ query = dict(urllib.parse.parse_qsl(parts.query, keep_blank_values=True))
21
+ query["wait"] = "true"
22
+
23
+ return urllib.parse.urlunsplit(
24
+ (parts.scheme, parts.netloc, parts.path, urllib.parse.urlencode(query), parts.fragment)
25
+ )
26
+
27
+
28
+ def _request_json(url: str, payload: dict[str, object], *, wait: bool, max_retries: int) -> dict[str, object] | None:
29
+ request_url = _with_wait_param(url, wait=wait)
30
+
31
+ headers = {
32
+ "Content-Type": "application/json",
33
+ "User-Agent": "OpenHands-DiscordSkill/1.0 (+https://github.com/OpenHands/skills)",
34
+ }
35
+
36
+ return post_json(
37
+ url=request_url,
38
+ headers=headers,
39
+ payload=payload,
40
+ max_retries=max_retries,
41
+ redact_url_in_errors=True,
42
+ )
43
+
44
+
45
+ def main() -> int:
46
+ parser = argparse.ArgumentParser(
47
+ description=(
48
+ "Post a message to a Discord incoming webhook. "
49
+ "The webhook URL is secret; avoid printing/logging it."
50
+ )
51
+ )
52
+ parser.add_argument(
53
+ "--webhook-url",
54
+ default=os.getenv("DISCORD_WEBHOOK_URL"),
55
+ help="Incoming webhook URL (default: $DISCORD_WEBHOOK_URL)",
56
+ )
57
+ parser.add_argument(
58
+ "--content",
59
+ help="Message content (max 2000 characters). If omitted, read from stdin.",
60
+ )
61
+ parser.add_argument(
62
+ "--wait",
63
+ action="store_true",
64
+ help="Add ?wait=true to get the created message object.",
65
+ )
66
+ parser.add_argument(
67
+ "--max-retries",
68
+ type=int,
69
+ default=3,
70
+ help="Retries on HTTP 429 (default: 3).",
71
+ )
72
+
73
+ args = parser.parse_args()
74
+
75
+ if not args.webhook_url:
76
+ print("Missing --webhook-url (or set DISCORD_WEBHOOK_URL).", file=sys.stderr)
77
+ return 2
78
+
79
+ content = args.content
80
+ if content is None:
81
+ content = sys.stdin.read().strip()
82
+
83
+ if not content:
84
+ print("No content provided (use --content or stdin).", file=sys.stderr)
85
+ return 2
86
+
87
+ payload = {
88
+ "content": content,
89
+ "allowed_mentions": {"parse": []},
90
+ }
91
+
92
+ result = _request_json(
93
+ args.webhook_url,
94
+ payload,
95
+ wait=args.wait,
96
+ max_retries=max(0, args.max_retries),
97
+ )
98
+
99
+ if result is not None:
100
+ print(json.dumps(result, indent=2, sort_keys=True))
101
+
102
+ return 0
103
+
104
+
105
+ if __name__ == "__main__":
106
+ raise SystemExit(main())
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import os
8
+ import sys
9
+ import urllib.request
10
+
11
+ from ._http import DiscordHTTPError, post_json
12
+
13
+
14
+ API_BASE = "https://discord.com/api/v10"
15
+
16
+
17
+ def _post_message(
18
+ *,
19
+ token: str,
20
+ channel_id: str,
21
+ payload: dict[str, object],
22
+ max_retries: int,
23
+ ) -> dict[str, object] | None:
24
+ url = f"{API_BASE}/channels/{channel_id}/messages"
25
+
26
+ headers = {
27
+ "Authorization": f"Bot {token}",
28
+ "Content-Type": "application/json",
29
+ "User-Agent": "OpenHands-DiscordSkill/1.0 (+https://github.com/OpenHands/skills)",
30
+ }
31
+
32
+ try:
33
+ return post_json(url=url, headers=headers, payload=payload, max_retries=max_retries)
34
+ except DiscordHTTPError as e:
35
+ raise DiscordHTTPError(f"Discord API call failed. channel_id={channel_id}. {e}") from e
36
+
37
+
38
+ def main() -> int:
39
+ parser = argparse.ArgumentParser(description="Send a message to a Discord channel using a bot token.")
40
+ parser.add_argument(
41
+ "--token",
42
+ default=os.getenv("DISCORD_BOT_TOKEN"),
43
+ help="Bot token (default: $DISCORD_BOT_TOKEN)",
44
+ )
45
+ parser.add_argument(
46
+ "--channel-id",
47
+ default=os.getenv("DISCORD_CHANNEL_ID"),
48
+ help="Channel ID (default: $DISCORD_CHANNEL_ID)",
49
+ )
50
+ parser.add_argument(
51
+ "--content",
52
+ help="Message content (max 2000 characters). If omitted, read from stdin.",
53
+ )
54
+ parser.add_argument(
55
+ "--max-retries",
56
+ type=int,
57
+ default=3,
58
+ help="Retries on HTTP 429 (default: 3).",
59
+ )
60
+ parser.add_argument(
61
+ "--allow-mentions",
62
+ action="store_true",
63
+ help="Allow Discord to parse mentions. Default is safe (no mentions).",
64
+ )
65
+
66
+ args = parser.parse_args()
67
+
68
+ if not args.token:
69
+ print("Missing --token (or set DISCORD_BOT_TOKEN).", file=sys.stderr)
70
+ return 2
71
+
72
+ if not args.channel_id:
73
+ print("Missing --channel-id (or set DISCORD_CHANNEL_ID).", file=sys.stderr)
74
+ return 2
75
+
76
+ content = args.content
77
+ if content is None:
78
+ content = sys.stdin.read().strip()
79
+
80
+ if not content:
81
+ print("No content provided (use --content or stdin).", file=sys.stderr)
82
+ return 2
83
+
84
+ payload: dict[str, object] = {"content": content}
85
+ if not args.allow_mentions:
86
+ payload["allowed_mentions"] = {"parse": []}
87
+
88
+ result = _post_message(
89
+ token=args.token,
90
+ channel_id=args.channel_id,
91
+ payload=payload,
92
+ max_retries=max(0, args.max_retries),
93
+ )
94
+
95
+ if result is not None:
96
+ print(json.dumps(result, indent=2, sort_keys=True))
97
+
98
+ return 0
99
+
100
+
101
+ if __name__ == "__main__":
102
+ raise SystemExit(main())
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "docker",
3
+ "version": "1.0.0",
4
+ "description": "Run Docker commands within a container environment, including starting the Docker daemon and managing containers. Use when building, running, or managing Docker containers and images.",
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
+ "docker",
14
+ "container",
15
+ "images"
16
+ ]
17
+ }
@@ -0,0 +1,34 @@
1
+ # Docker
2
+
3
+ Run Docker commands within a container environment, including starting the Docker daemon and managing containers. Use when building, running, or managing Docker containers and images.
4
+
5
+ ## Triggers
6
+
7
+ This skill is activated by the following keywords:
8
+
9
+ - `docker`
10
+ - `container`
11
+
12
+ ## Details
13
+
14
+ # Docker Usage Guide
15
+
16
+ ## Starting Docker in Container Environments
17
+
18
+ Please check if docker is already installed. If so, to start Docker in a container environment:
19
+
20
+ ```bash
21
+ # Start Docker daemon in the background
22
+ sudo dockerd > /tmp/docker.log 2>&1 &
23
+
24
+ # Wait for Docker to initialize
25
+ sleep 5
26
+ ```
27
+
28
+ ## Verifying Docker Installation
29
+
30
+ To verify Docker is working correctly, run the hello-world container:
31
+
32
+ ```bash
33
+ sudo docker run hello-world
34
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: docker
3
+ description: Run Docker commands within a container environment, including starting the Docker daemon and managing containers. Use when building, running, or managing Docker containers and images.
4
+ triggers:
5
+ - docker
6
+ - container
7
+ ---
8
+
9
+ # Docker Usage Guide
10
+
11
+ ## Starting Docker in Container Environments
12
+
13
+ Please check if docker is already installed. If so, to start Docker in a container environment:
14
+
15
+ ```bash
16
+ # Start Docker daemon in the background
17
+ sudo dockerd > /tmp/docker.log 2>&1 &
18
+
19
+ # Wait for Docker to initialize
20
+ sleep 5
21
+ ```
22
+
23
+ ## Verifying Docker Installation
24
+
25
+ To verify Docker is working correctly, run the hello-world container:
26
+
27
+ ```bash
28
+ sudo docker run hello-world
29
+ ```
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "evidence-based-citations",
3
+ "version": "1.0.0",
4
+ "description": "Back factual claims and field values with official, verifiable sources. Use when the user asks to fill fields, answer questions, or make claims that must be supported by an exact quote and an official link.",
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
+ "evidence",
14
+ "citations",
15
+ "sources",
16
+ "verification",
17
+ "documentation",
18
+ "official"
19
+ ]
20
+ }
@@ -0,0 +1,31 @@
1
+ # Evidence-Based Citations
2
+
3
+ Back factual claims and field values with official, verifiable sources. Use when the user asks to fill fields, answer questions, or make claims that must be supported by an exact quote and an official link.
4
+
5
+ ## Triggers
6
+
7
+ This skill is activated by the following keywords:
8
+
9
+ - `evidence-based`
10
+ - `cite source` / `cite sources`
11
+ - `official source` / `official link` / `official links`
12
+ - `official docs` / `official documentation`
13
+ - `verifiable source`
14
+
15
+ ## What it does
16
+
17
+ When activated, the agent reports every field value or factual claim using four labeled lines:
18
+
19
+ - **Field** - the field name or short claim description
20
+ - **Value** - the value being assigned
21
+ - **Quote** - the verbatim text from the source supporting the value
22
+ - **Source** - the official URL where the quote can be found
23
+
24
+ ## Source rules
25
+
26
+ - Prefer primary sources (official docs, RFCs, API references, source code).
27
+ - Fall back to secondary sources (blogs, forums) only when necessary, and label them.
28
+ - The quote must appear verbatim at the source URL.
29
+ - If no official source can be found, say `Source: No official source found.` rather than fabricating a reference.
30
+
31
+ See [`SKILL.md`](./SKILL.md) for the full prompt the agent loads when this skill is triggered.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: evidence-based-citations
3
+ description: Back factual claims and field values with official, verifiable sources. Use when the user asks to fill fields, answer questions, or make claims that must be supported by an exact quote and an official link.
4
+ triggers:
5
+ - evidence-based
6
+ - cite source
7
+ - cite sources
8
+ - official source
9
+ - official link
10
+ - official links
11
+ - official docs
12
+ - official documentation
13
+ - verifiable source
14
+ ---
15
+
16
+ The user wants every field value or factual claim you produce in the current response to be backed by an official, verifiable source. Apply this skill to the response that triggered it; do not assume it stays active for the rest of the conversation unless the user clearly asks for it to.
17
+
18
+ ## Output format
19
+
20
+ For each field or claim, respond with exactly these four labeled lines:
21
+
22
+ - **Field**: the field name (or a short description of the claim)
23
+ - **Value**: the value you are assigning (or the claim itself)
24
+ - **Quote**: the exact verbatim text from the source that supports the value
25
+ - **Source**: the official URL where the quote can be found
26
+
27
+ When there are multiple fields, repeat the block once per field. Keep blocks separated by a blank line.
28
+
29
+ ## Source selection rules
30
+
31
+ 1. Prefer primary sources, in this order:
32
+ - Official product / project documentation
33
+ - Standards documents (RFCs, W3C specs, ISO standards)
34
+ - Official API references
35
+ - Source code in the project's own repository
36
+ 2. Accept secondary sources (blog posts, Stack Overflow, forum threads, news articles, third-party tutorials) only as a last resort, and clearly label them as such in **Source**.
37
+ 3. The **Quote** field must contain text that actually appears at the **Source** URL. Do not paraphrase inside the quote, and do not stitch together text from different parts of the page without making the cut explicit (e.g. with ` … `).
38
+ 4. If you cannot find an official source for a value, say so explicitly:
39
+ - **Source**: `No official source found.`
40
+ Then either omit the value, mark it as unverified, or ask the user how to proceed. Never invent a quote or URL.
41
+
42
+ ## When to fetch
43
+
44
+ - If you have a browser / fetch tool available, retrieve the source page and copy the quote directly from it before responding.
45
+ - If you do not have a fetch tool, always respond with `Source: No official source found.` rather than citing URLs from memory. LLMs cannot reliably verify URL accuracy or quote fidelity without actually fetching the page, even when a URL feels familiar.
46
+
47
+ ## Example
48
+
49
+ > User: What HTTP status code indicates a successful request, per the HTTP semantics RFC?
50
+
51
+ - **Field**: HTTP status code for a successful request (per RFC 9110)
52
+ - **Value**: 200 (OK)
53
+ - **Quote**: "The 200 (OK) status code indicates that the request has succeeded."
54
+ - **Source**: https://www.rfc-editor.org/rfc/rfc9110.html#section-15.3.1
55
+
56
+ ## What this skill is not
57
+
58
+ - It is not a general "be careful with facts" reminder. Apply the strict four-field format only when the user has invoked this skill or is clearly asking for evidence-backed answers.
59
+ - It does not change how you write code, edit files, or run tools. It only governs how you report values and claims back to the user.
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "flarglebargle",
3
+ "version": "1.0.0",
4
+ "description": "A test skill that responds to the magic word 'flarglebargle' with a compliment. Use for testing skill activation and trigger functionality.",
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
+ "test",
14
+ "demo"
15
+ ]
16
+ }
@@ -0,0 +1,14 @@
1
+ # Flarglebargle
2
+
3
+ A test skill that responds to the magic word "flarglebargle" with a compliment. Use for testing skill activation and trigger functionality.
4
+
5
+ ## Triggers
6
+
7
+ This skill is activated by the following keywords:
8
+
9
+ - `flarglebargle`
10
+
11
+ ## Details
12
+
13
+ IMPORTANT! The user has said the magic word "flarglebargle". You must
14
+ only respond with a message telling them how smart they are
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: flarglebargle
3
+ description: A test skill that responds to the magic word "flarglebargle" with a compliment. Use for testing skill activation and trigger functionality.
4
+ triggers:
5
+ - flarglebargle
6
+ ---
7
+
8
+ IMPORTANT! The user has said the magic word "flarglebargle". You must
9
+ only respond with a message telling them how smart they are
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "frontend-design",
3
+ "version": "1.0.0",
4
+ "description": "Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications. Generates c...",
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
+ "frontend",
14
+ "design",
15
+ "ui",
16
+ "web",
17
+ "react",
18
+ "html",
19
+ "css"
20
+ ]
21
+ }