@openhands/extensions 0.19.0 → 0.21.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 (64) hide show
  1. package/.github/workflows/check-extensions.yml +4 -0
  2. package/.github/workflows/pr-artifacts.yml +294 -0
  3. package/.github/workflows/pr-description-check.yml +4 -2
  4. package/.release-please-manifest.json +1 -1
  5. package/AGENTS.md +28 -4
  6. package/README.md +5 -2
  7. package/automations/README.md +52 -36
  8. package/automations/bundle-index.js +13 -3
  9. package/automations/catalog/custom-automation/manifest.json +229 -0
  10. package/automations/catalog/github-agents-md-maintainer/manifest.json +2 -1
  11. package/automations/catalog/github-issue-to-pr/manifest.json +3 -2
  12. package/automations/catalog/github-issue-triage/manifest.json +72 -0
  13. package/automations/catalog/github-pr-reviewer/manifest.json +3 -2
  14. package/automations/catalog/gitlab-issue-to-mr/manifest.json +124 -0
  15. package/automations/catalog/qa-changes/manifest.json +1 -1
  16. package/automations/catalog-index.js +23 -17
  17. package/automations/catalog.schema.json +81 -7
  18. package/automations/index.d.ts +52 -2
  19. package/automations/interface.json +2 -1
  20. package/integrations/catalog/gitlab.json +27 -5
  21. package/integrations/catalog/reportportal.json +76 -0
  22. package/integrations/catalog-index.js +6 -4
  23. package/marketplaces/openhands-extensions.json +36 -0
  24. package/package.json +1 -1
  25. package/pyproject.toml +2 -2
  26. package/python/openhands_extensions/_version.py +1 -1
  27. package/skills/github/scripts/github_client.py +204 -0
  28. package/skills/github-agents-md-maintainer/SKILL.md +7 -1
  29. package/skills/github-agents-md-maintainer/scripts/main.py +4 -40
  30. package/skills/github-issue-to-pr/SKILL.md +8 -1
  31. package/skills/github-issue-to-pr/scripts/main.py +3 -40
  32. package/skills/github-issue-triage/.plugin/plugin.json +9 -0
  33. package/skills/github-issue-triage/README.md +9 -0
  34. package/skills/github-issue-triage/SKILL.md +37 -0
  35. package/skills/github-issue-triage/commands/github-issue-triage.md +8 -0
  36. package/skills/github-issue-triage/scripts/worker.py +123 -0
  37. package/skills/github-pr-reviewer/SKILL.md +8 -1
  38. package/skills/github-pr-reviewer/scripts/main.py +3 -41
  39. package/skills/github-repo-monitor/SKILL.md +7 -1
  40. package/skills/github-repo-monitor/scripts/main.py +4 -46
  41. package/skills/gitlab-issue-to-mr/.plugin/plugin.json +19 -0
  42. package/skills/gitlab-issue-to-mr/README.md +92 -0
  43. package/skills/gitlab-issue-to-mr/SKILL.md +408 -0
  44. package/skills/gitlab-issue-to-mr/commands/issue-to-mr-setup.md +8 -0
  45. package/skills/gitlab-issue-to-mr/references/state-schema.md +140 -0
  46. package/skills/gitlab-issue-to-mr/scripts/main.py +1448 -0
  47. package/skills/index.js +43 -6
  48. package/skills/openhands-automation/README.md +1 -1
  49. package/skills/openhands-automation/SKILL.md +18 -8
  50. package/skills/openhands-enterprise-troubleshooting/.plugin/plugin.json +20 -0
  51. package/skills/openhands-enterprise-troubleshooting/README.md +79 -0
  52. package/skills/openhands-enterprise-troubleshooting/SKILL.md +339 -0
  53. package/skills/openhands-enterprise-troubleshooting/references/diagnostics.md +698 -0
  54. package/skills/openhands-enterprise-troubleshooting/references/support-bundle-analysis.md +570 -0
  55. package/skills/openhands-enterprise-troubleshooting/scripts/bundle_triage.py +532 -0
  56. package/skills/openhands-sdk/SKILL.md +2 -0
  57. package/tests/fixtures/automations/custom-automation.json +398 -0
  58. package/tests/fixtures/automations/github-pr-reviewer.json +9 -9
  59. package/tests/github_automation_helpers.py +25 -0
  60. package/tests/test_automation_setup.py +340 -92
  61. package/tests/test_github_automation_foundation.py +73 -0
  62. package/tests/test_github_skill_installation.py +63 -0
  63. package/tests/test_github_triage_delivery.py +53 -0
  64. package/tests/test_gitlab_issue_to_mr.py +823 -0
@@ -0,0 +1,398 @@
1
+ {
2
+ "automationId": "custom-automation",
3
+ "description": "Direct generic setup. One catalog entry can create prompt, plugin, or uploaded-tarball automations; selectedAction and selectedTrigger record the host UI variants chosen for each scenario.",
4
+ "capabilities": "supported",
5
+ "blockedBy": [
6
+ "notReady"
7
+ ],
8
+ "scenarios": [
9
+ {
10
+ "id": "scheduled-prompt",
11
+ "description": "A custom prompt automation that runs on a weekday schedule and clones one repository.",
12
+ "selectedAction": "prompt",
13
+ "selectedTrigger": "cron",
14
+ "formValues": {
15
+ "name": "Daily extensions summary",
16
+ "prompt": "Summarize recent changes in the OpenHands/extensions repository and save a concise report in the workspace.",
17
+ "repository": "OpenHands/extensions",
18
+ "ref": "main",
19
+ "model": "fast",
20
+ "timeout": 900,
21
+ "schedule": "0 9 * * 1-5",
22
+ "timezone": "UTC"
23
+ },
24
+ "preflight": {
25
+ "request": {
26
+ "method": "POST",
27
+ "path": "/v1/validate",
28
+ "body": {
29
+ "automationId": "custom-automation",
30
+ "endpoint": "/v1/preset/prompt",
31
+ "draft": {
32
+ "name": "Daily extensions summary",
33
+ "prompt": "Summarize recent changes in the OpenHands/extensions repository and save a concise report in the workspace.",
34
+ "model": "fast",
35
+ "timeout": 900,
36
+ "repos": [
37
+ {
38
+ "url": "OpenHands/extensions",
39
+ "provider": "github",
40
+ "ref": "main"
41
+ }
42
+ ],
43
+ "trigger": {
44
+ "type": "cron",
45
+ "schedule": "0 9 * * 1-5",
46
+ "timezone": "UTC"
47
+ }
48
+ }
49
+ }
50
+ },
51
+ "response": {
52
+ "status": 200,
53
+ "body": {
54
+ "valid": true,
55
+ "errors": []
56
+ }
57
+ }
58
+ },
59
+ "create": {
60
+ "request": {
61
+ "method": "POST",
62
+ "path": "/v1/preset/prompt",
63
+ "body": {
64
+ "name": "Daily extensions summary",
65
+ "prompt": "Summarize recent changes in the OpenHands/extensions repository and save a concise report in the workspace.",
66
+ "model": "fast",
67
+ "timeout": 900,
68
+ "repos": [
69
+ {
70
+ "url": "OpenHands/extensions",
71
+ "provider": "github",
72
+ "ref": "main"
73
+ }
74
+ ],
75
+ "trigger": {
76
+ "type": "cron",
77
+ "schedule": "0 9 * * 1-5",
78
+ "timezone": "UTC"
79
+ }
80
+ }
81
+ },
82
+ "response": {
83
+ "status": 201,
84
+ "body": {
85
+ "id": "1c0b7ea0-0000-4000-8000-000000000001",
86
+ "model": "fast",
87
+ "name": "Daily extensions summary",
88
+ "prompt": "Summarize recent changes in the OpenHands/extensions repository and save a concise report in the workspace.",
89
+ "trigger": {
90
+ "type": "cron",
91
+ "schedule": "0 9 * * 1-5",
92
+ "timezone": "UTC"
93
+ },
94
+ "timeout": 900,
95
+ "enabled": true
96
+ }
97
+ }
98
+ }
99
+ },
100
+ {
101
+ "id": "event-prompt",
102
+ "description": "A custom prompt automation that runs on a GitHub comment event.",
103
+ "selectedAction": "prompt",
104
+ "selectedTrigger": "event",
105
+ "formValues": {
106
+ "name": "OpenHands mention responder",
107
+ "prompt": "When triggered, read the GitHub issue or pull request context and draft a helpful response for the user.",
108
+ "repository": "OpenHands/extensions",
109
+ "ref": "main",
110
+ "model": "",
111
+ "timeout": 600,
112
+ "source": "github",
113
+ "on": "issue_comment.created",
114
+ "filter": "glob(repository.full_name, 'OpenHands/extensions') && icontains(comment.body, '@openhands')"
115
+ },
116
+ "preflight": {
117
+ "request": {
118
+ "method": "POST",
119
+ "path": "/v1/validate",
120
+ "body": {
121
+ "automationId": "custom-automation",
122
+ "endpoint": "/v1/preset/prompt",
123
+ "draft": {
124
+ "name": "OpenHands mention responder",
125
+ "prompt": "When triggered, read the GitHub issue or pull request context and draft a helpful response for the user.",
126
+ "timeout": 600,
127
+ "repos": [
128
+ {
129
+ "url": "OpenHands/extensions",
130
+ "provider": "github",
131
+ "ref": "main"
132
+ }
133
+ ],
134
+ "trigger": {
135
+ "type": "event",
136
+ "source": "github",
137
+ "on": "issue_comment.created",
138
+ "filter": "glob(repository.full_name, 'OpenHands/extensions') && icontains(comment.body, '@openhands')"
139
+ }
140
+ }
141
+ }
142
+ },
143
+ "response": {
144
+ "status": 200,
145
+ "body": {
146
+ "valid": true,
147
+ "errors": []
148
+ }
149
+ }
150
+ },
151
+ "create": {
152
+ "request": {
153
+ "method": "POST",
154
+ "path": "/v1/preset/prompt",
155
+ "body": {
156
+ "name": "OpenHands mention responder",
157
+ "prompt": "When triggered, read the GitHub issue or pull request context and draft a helpful response for the user.",
158
+ "timeout": 600,
159
+ "repos": [
160
+ {
161
+ "url": "OpenHands/extensions",
162
+ "provider": "github",
163
+ "ref": "main"
164
+ }
165
+ ],
166
+ "trigger": {
167
+ "type": "event",
168
+ "source": "github",
169
+ "on": "issue_comment.created",
170
+ "filter": "glob(repository.full_name, 'OpenHands/extensions') && icontains(comment.body, '@openhands')"
171
+ }
172
+ }
173
+ },
174
+ "response": {
175
+ "status": 201,
176
+ "body": {
177
+ "id": "1c0b7ea0-0000-4000-8000-000000000002",
178
+ "model": null,
179
+ "name": "OpenHands mention responder",
180
+ "prompt": "When triggered, read the GitHub issue or pull request context and draft a helpful response for the user.",
181
+ "trigger": {
182
+ "type": "event",
183
+ "source": "github",
184
+ "on": "issue_comment.created",
185
+ "filter": "glob(repository.full_name, 'OpenHands/extensions') && icontains(comment.body, '@openhands')"
186
+ },
187
+ "timeout": 600,
188
+ "enabled": true
189
+ }
190
+ }
191
+ }
192
+ },
193
+ {
194
+ "id": "scheduled-plugin",
195
+ "description": "A custom plugin automation that loads an OpenHands plugin and runs a prompt.",
196
+ "selectedAction": "plugin",
197
+ "selectedTrigger": "cron",
198
+ "formValues": {
199
+ "name": "Weekly plugin check",
200
+ "plugins": [
201
+ {
202
+ "source": "github:OpenHands/extensions",
203
+ "repo_path": "plugins/qa-changes",
204
+ "ref": "main"
205
+ }
206
+ ],
207
+ "prompt": "Use the plugin to QA recent changes and produce a concise report.",
208
+ "repository": "OpenHands/OpenHands",
209
+ "ref": "main",
210
+ "model": "balanced",
211
+ "timeout": 1200,
212
+ "schedule": "0 10 * * 1",
213
+ "timezone": "UTC"
214
+ },
215
+ "preflight": {
216
+ "request": {
217
+ "method": "POST",
218
+ "path": "/v1/validate",
219
+ "body": {
220
+ "automationId": "custom-automation",
221
+ "endpoint": "/v1/preset/plugin",
222
+ "draft": {
223
+ "name": "Weekly plugin check",
224
+ "prompt": "Use the plugin to QA recent changes and produce a concise report.",
225
+ "plugins": [
226
+ {
227
+ "source": "github:OpenHands/extensions",
228
+ "repo_path": "plugins/qa-changes",
229
+ "ref": "main"
230
+ }
231
+ ],
232
+ "model": "balanced",
233
+ "timeout": 1200,
234
+ "repos": [
235
+ {
236
+ "url": "OpenHands/OpenHands",
237
+ "provider": "github",
238
+ "ref": "main"
239
+ }
240
+ ],
241
+ "trigger": {
242
+ "type": "cron",
243
+ "schedule": "0 10 * * 1",
244
+ "timezone": "UTC"
245
+ }
246
+ }
247
+ }
248
+ },
249
+ "response": {
250
+ "status": 200,
251
+ "body": {
252
+ "valid": true,
253
+ "errors": []
254
+ }
255
+ }
256
+ },
257
+ "create": {
258
+ "request": {
259
+ "method": "POST",
260
+ "path": "/v1/preset/plugin",
261
+ "body": {
262
+ "name": "Weekly plugin check",
263
+ "prompt": "Use the plugin to QA recent changes and produce a concise report.",
264
+ "plugins": [
265
+ {
266
+ "source": "github:OpenHands/extensions",
267
+ "repo_path": "plugins/qa-changes",
268
+ "ref": "main"
269
+ }
270
+ ],
271
+ "model": "balanced",
272
+ "timeout": 1200,
273
+ "repos": [
274
+ {
275
+ "url": "OpenHands/OpenHands",
276
+ "provider": "github",
277
+ "ref": "main"
278
+ }
279
+ ],
280
+ "trigger": {
281
+ "type": "cron",
282
+ "schedule": "0 10 * * 1",
283
+ "timezone": "UTC"
284
+ }
285
+ }
286
+ },
287
+ "response": {
288
+ "status": 201,
289
+ "body": {
290
+ "id": "1c0b7ea0-0000-4000-8000-000000000003",
291
+ "model": "balanced",
292
+ "name": "Weekly plugin check",
293
+ "prompt": "Use the plugin to QA recent changes and produce a concise report.",
294
+ "trigger": {
295
+ "type": "cron",
296
+ "schedule": "0 10 * * 1",
297
+ "timezone": "UTC"
298
+ },
299
+ "timeout": 1200,
300
+ "enabled": true
301
+ }
302
+ }
303
+ }
304
+ },
305
+ {
306
+ "id": "scheduled-upload",
307
+ "description": "A custom upload automation that uploads a tarball and creates through the raw endpoint.",
308
+ "selectedAction": "upload",
309
+ "selectedTrigger": "cron",
310
+ "formValues": {
311
+ "name": "Uploaded maintenance script",
312
+ "tarball": "oh-internal://uploads/1c0b7ea0-0000-4000-8000-000000000004",
313
+ "entrypoint": "python3 main.py",
314
+ "setupScript": "setup.sh",
315
+ "model": "",
316
+ "timeout": 300,
317
+ "schedule": "30 2 * * *",
318
+ "timezone": "UTC"
319
+ },
320
+ "upload": {
321
+ "request": {
322
+ "method": "POST",
323
+ "path": "/v1/uploads?name=Uploaded%20maintenance%20script"
324
+ },
325
+ "response": {
326
+ "status": 201,
327
+ "body": {
328
+ "id": "1c0b7ea0-0000-4000-8000-000000000004",
329
+ "status": "COMPLETED",
330
+ "tarball_path": "oh-internal://uploads/1c0b7ea0-0000-4000-8000-000000000004"
331
+ }
332
+ }
333
+ },
334
+ "preflight": {
335
+ "request": {
336
+ "method": "POST",
337
+ "path": "/v1/validate",
338
+ "body": {
339
+ "automationId": "custom-automation",
340
+ "endpoint": "/v1",
341
+ "draft": {
342
+ "name": "Uploaded maintenance script",
343
+ "timeout": 300,
344
+ "trigger": {
345
+ "type": "cron",
346
+ "schedule": "30 2 * * *",
347
+ "timezone": "UTC"
348
+ },
349
+ "tarball_path": "oh-internal://uploads/00000000-0000-0000-0000-000000000000",
350
+ "entrypoint": "python3 main.py",
351
+ "setup_script_path": "setup.sh"
352
+ }
353
+ }
354
+ },
355
+ "response": {
356
+ "status": 200,
357
+ "body": {
358
+ "valid": true,
359
+ "errors": []
360
+ }
361
+ }
362
+ },
363
+ "create": {
364
+ "request": {
365
+ "method": "POST",
366
+ "path": "/v1",
367
+ "body": {
368
+ "name": "Uploaded maintenance script",
369
+ "timeout": 300,
370
+ "trigger": {
371
+ "type": "cron",
372
+ "schedule": "30 2 * * *",
373
+ "timezone": "UTC"
374
+ },
375
+ "tarball_path": "oh-internal://uploads/1c0b7ea0-0000-4000-8000-000000000004",
376
+ "entrypoint": "python3 main.py",
377
+ "setup_script_path": "setup.sh"
378
+ }
379
+ },
380
+ "response": {
381
+ "status": 201,
382
+ "body": {
383
+ "id": "1c0b7ea0-0000-4000-8000-000000000004",
384
+ "model": null,
385
+ "name": "Uploaded maintenance script",
386
+ "trigger": {
387
+ "type": "cron",
388
+ "schedule": "30 2 * * *",
389
+ "timezone": "UTC"
390
+ },
391
+ "timeout": 300,
392
+ "enabled": true
393
+ }
394
+ }
395
+ }
396
+ }
397
+ ]
398
+ }
@@ -50,7 +50,7 @@
50
50
  "automationId": "github-pr-reviewer",
51
51
  "endpoint": "/v1",
52
52
  "draft": {
53
- "name": "GitHub Code Review Agent - OpenHands/agent-server-gui",
53
+ "name": "GitHub code review - OpenHands/agent-server-gui",
54
54
  "trigger": {
55
55
  "type": "cron",
56
56
  "schedule": "*/15 * * * *",
@@ -86,7 +86,7 @@
86
86
  "method": "POST",
87
87
  "path": "/v1",
88
88
  "body": {
89
- "name": "GitHub Code Review Agent - OpenHands/agent-server-gui",
89
+ "name": "GitHub code review - OpenHands/agent-server-gui",
90
90
  "trigger": {
91
91
  "type": "cron",
92
92
  "schedule": "*/15 * * * *",
@@ -115,7 +115,7 @@
115
115
  "user_id": "1a2b3c4d-0000-4000-8000-000000000001",
116
116
  "org_id": "1a2b3c4d-0000-4000-8000-000000000002",
117
117
  "model": null,
118
- "name": "GitHub Code Review Agent - OpenHands/agent-server-gui",
118
+ "name": "GitHub code review - OpenHands/agent-server-gui",
119
119
  "prompt": "Review pull requests labeled 'openhands-review' in OpenHands/agent-server-gui. Review tone: thorough.",
120
120
  "trigger": {
121
121
  "type": "cron",
@@ -179,7 +179,7 @@
179
179
  "automationId": "github-pr-reviewer",
180
180
  "endpoint": "/v1",
181
181
  "draft": {
182
- "name": "GitHub Code Review Agent - 2 repositories",
182
+ "name": "GitHub code review - 2 repositories",
183
183
  "trigger": {
184
184
  "type": "cron",
185
185
  "schedule": "*/15 * * * *",
@@ -216,7 +216,7 @@
216
216
  "method": "POST",
217
217
  "path": "/v1",
218
218
  "body": {
219
- "name": "GitHub Code Review Agent - 2 repositories",
219
+ "name": "GitHub code review - 2 repositories",
220
220
  "trigger": {
221
221
  "type": "cron",
222
222
  "schedule": "*/15 * * * *",
@@ -246,7 +246,7 @@
246
246
  "user_id": "1a2b3c4d-0000-4000-8000-000000000001",
247
247
  "org_id": "1a2b3c4d-0000-4000-8000-000000000002",
248
248
  "model": null,
249
- "name": "GitHub Code Review Agent - 2 repositories",
249
+ "name": "GitHub code review - 2 repositories",
250
250
  "prompt": "Review pull requests labeled 'openhands-review' in OpenHands/agent-server-gui. Review tone: thorough.",
251
251
  "trigger": {
252
252
  "type": "cron",
@@ -300,7 +300,7 @@
300
300
  "automationId": "github-pr-reviewer",
301
301
  "endpoint": "/v1",
302
302
  "draft": {
303
- "name": "GitHub Code Review Agent - OpenHands/agent-server-gui",
303
+ "name": "GitHub code review - OpenHands/agent-server-gui",
304
304
  "trigger": {
305
305
  "type": "cron",
306
306
  "schedule": "*/1 * * * *",
@@ -381,7 +381,7 @@
381
381
  "method": "POST",
382
382
  "path": "/v1",
383
383
  "body": {
384
- "name": "GitHub Code Review Agent - OpenHands/agent-server-gui",
384
+ "name": "GitHub code review - OpenHands/agent-server-gui",
385
385
  "trigger": {
386
386
  "type": "cron",
387
387
  "schedule": "0 0 31 2 *",
@@ -465,7 +465,7 @@
465
465
  "method": "POST",
466
466
  "path": "/v1",
467
467
  "body": {
468
- "name": "GitHub Code Review Agent - OpenHands/agent-server-gui",
468
+ "name": "GitHub code review - OpenHands/agent-server-gui",
469
469
  "trigger": {
470
470
  "type": "cron",
471
471
  "schedule": "*/15 * * * *",
@@ -0,0 +1,25 @@
1
+ """Exercise the actual shipped entrypoints with mocked GitHub/SDK boundaries."""
2
+
3
+ import importlib.util
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ ROOT = Path(__file__).resolve().parents[1]
9
+
10
+
11
+ def worker(name, tmp_path, monkeypatch):
12
+ manifest = json.loads(
13
+ (ROOT / f"automations/catalog/{name}/manifest.json").read_text()
14
+ )
15
+ bundle = tmp_path / name
16
+ bundle.mkdir()
17
+ for filename, source in manifest["setup"]["bundle"]["files"].items():
18
+ (bundle / filename).write_text((ROOT / source).read_text())
19
+ for module in ("main", "github_client", "qa_prompt", "worker"):
20
+ monkeypatch.delitem(sys.modules, module, raising=False)
21
+ monkeypatch.syspath_prepend(str(bundle))
22
+ spec = importlib.util.spec_from_file_location("worker", bundle / "worker.py")
23
+ module = importlib.util.module_from_spec(spec)
24
+ spec.loader.exec_module(module)
25
+ return module