@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.
- package/.claude-plugin/marketplace.json +881 -0
- package/.codex-plugin/marketplace.json +881 -0
- package/.github/workflows/check-extensions.yml +4 -0
- package/.github/workflows/npm-publish.yml +9 -3
- package/.github/workflows/pr-artifacts.yml +294 -0
- package/.github/workflows/pr-description-check.yml +4 -2
- package/.plugin/marketplace.json +881 -0
- package/.release-please-manifest.json +1 -1
- package/AGENTS.md +27 -3
- package/README.md +6 -2
- package/automations/bundle-index.js +22 -3
- package/automations/catalog/github-agents-md-maintainer/manifest.json +2 -1
- package/automations/catalog/github-delivery-watchdog/manifest.json +79 -0
- package/automations/catalog/github-issue-to-pr/manifest.json +24 -15
- package/automations/catalog/github-issue-triage/manifest.json +73 -0
- package/automations/catalog/github-pr-reviewer/manifest.json +23 -15
- package/automations/catalog/gitlab-issue-to-mr/manifest.json +124 -0
- package/automations/catalog-index.js +17 -11
- package/integrations/catalog/reportportal.json +76 -0
- package/integrations/catalog-index.js +6 -4
- package/marketplaces/openhands-extensions.json +42 -0
- package/package.json +1 -1
- package/plugins/city-weather/.claude-plugin/plugin.json +13 -0
- package/plugins/city-weather/.codex-plugin/plugin.json +13 -0
- package/plugins/cobol-modernization/.claude-plugin/plugin.json +19 -0
- package/plugins/cobol-modernization/.codex-plugin/plugin.json +19 -0
- package/plugins/issue-duplicate-checker/.claude-plugin/plugin.json +13 -0
- package/plugins/issue-duplicate-checker/.codex-plugin/plugin.json +13 -0
- package/plugins/magic-test/.claude-plugin/plugin.json +13 -0
- package/plugins/magic-test/.codex-plugin/plugin.json +13 -0
- package/plugins/migration-scoring/.claude-plugin/plugin.json +19 -0
- package/plugins/migration-scoring/.codex-plugin/plugin.json +19 -0
- package/plugins/onboarding/.claude-plugin/plugin.json +20 -0
- package/plugins/onboarding/.codex-plugin/plugin.json +20 -0
- package/plugins/onboarding/skills/agent-readiness-report/references/criteria.md +144 -0
- package/plugins/onboarding/skills/improve-agent-readiness/references/criteria.md +144 -0
- package/plugins/openhands/.claude-plugin/plugin.json +13 -0
- package/plugins/openhands/.codex-plugin/plugin.json +13 -0
- package/plugins/openhands/skills/openhands-api/.claude-plugin/plugin.json +22 -0
- package/plugins/openhands/skills/openhands-api/.codex-plugin/plugin.json +22 -0
- package/plugins/openhands/skills/openhands-api/.plugin/plugin.json +22 -0
- package/plugins/openhands/skills/openhands-api/README.md +52 -0
- package/plugins/openhands/skills/openhands-api/SKILL.md +469 -0
- package/plugins/openhands/skills/openhands-api/references/README.md +33 -0
- package/plugins/openhands/skills/openhands-api/references/TROUBLESHOOTING.md +81 -0
- package/plugins/openhands/skills/openhands-api/references/example_prompt.md +12 -0
- package/plugins/openhands/skills/openhands-api/references/windows.md +44 -0
- package/plugins/openhands/skills/openhands-api/scripts/openhands_api.py +606 -0
- package/plugins/openhands/skills/openhands-api/scripts/openhands_api.ts +252 -0
- package/plugins/openhands/skills/openhands-automation/.claude-plugin/plugin.json +19 -0
- package/plugins/openhands/skills/openhands-automation/.codex-plugin/plugin.json +19 -0
- package/plugins/openhands/skills/openhands-automation/.plugin/plugin.json +19 -0
- package/plugins/openhands/skills/openhands-automation/README.md +89 -0
- package/plugins/openhands/skills/openhands-automation/SKILL.md +899 -0
- package/plugins/openhands/skills/openhands-automation/commands/automation-create.md +8 -0
- package/plugins/openhands/skills/openhands-automation/references/ab-testing.md +185 -0
- package/plugins/openhands/skills/openhands-automation/references/custom-automation.md +832 -0
- package/plugins/openhands/skills/openhands-automation/references/security.md +84 -0
- package/plugins/openhands/skills/openhands-automation/references/windows.md +57 -0
- package/plugins/openhands/skills/openhands-sdk/.claude-plugin/plugin.json +20 -0
- package/plugins/openhands/skills/openhands-sdk/.codex-plugin/plugin.json +20 -0
- package/plugins/openhands/skills/openhands-sdk/.plugin/plugin.json +20 -0
- package/plugins/openhands/skills/openhands-sdk/README.md +22 -0
- package/plugins/openhands/skills/openhands-sdk/SKILL.md +245 -0
- package/plugins/openhands/skills/openhands-sdk/commands/sdk.md +8 -0
- package/plugins/pr-review/.claude-plugin/plugin.json +13 -0
- package/plugins/pr-review/.codex-plugin/plugin.json +13 -0
- package/plugins/pr-review/skills/code-review/.claude-plugin/plugin.json +19 -0
- package/plugins/pr-review/skills/code-review/.codex-plugin/plugin.json +19 -0
- package/plugins/pr-review/skills/code-review/.plugin/plugin.json +19 -0
- package/plugins/pr-review/skills/code-review/README.md +18 -0
- package/plugins/pr-review/skills/code-review/SKILL.md +209 -0
- package/plugins/pr-review/skills/code-review/commands/codereview-roasted.md +8 -0
- package/plugins/pr-review/skills/code-review/commands/codereview.md +8 -0
- package/plugins/pr-review/skills/code-review/references/risk-evaluation.md +41 -0
- package/plugins/pr-review/skills/code-review/references/supply-chain-security.md +31 -0
- package/plugins/pr-review/skills/github-pr-review/.claude-plugin/plugin.json +18 -0
- package/plugins/pr-review/skills/github-pr-review/.codex-plugin/plugin.json +18 -0
- package/plugins/pr-review/skills/github-pr-review/.plugin/plugin.json +18 -0
- package/plugins/pr-review/skills/github-pr-review/README.md +145 -0
- package/plugins/pr-review/skills/github-pr-review/SKILL.md +187 -0
- package/plugins/pr-review/skills/github-pr-review/commands/github-pr-review.md +8 -0
- package/plugins/pr-review/skills/github-pr-review/references/windows.md +47 -0
- package/plugins/qa-changes/.claude-plugin/plugin.json +11 -0
- package/plugins/qa-changes/.codex-plugin/plugin.json +11 -0
- package/plugins/qa-changes/skills/github-pr-review/.claude-plugin/plugin.json +18 -0
- package/plugins/qa-changes/skills/github-pr-review/.codex-plugin/plugin.json +18 -0
- package/plugins/qa-changes/skills/github-pr-review/.plugin/plugin.json +18 -0
- package/plugins/qa-changes/skills/github-pr-review/README.md +145 -0
- package/plugins/qa-changes/skills/github-pr-review/SKILL.md +187 -0
- package/plugins/qa-changes/skills/github-pr-review/commands/github-pr-review.md +8 -0
- package/plugins/qa-changes/skills/github-pr-review/references/windows.md +47 -0
- package/plugins/qa-changes/skills/qa-changes/README.md +18 -0
- package/plugins/qa-changes/skills/qa-changes/SKILL.md +229 -0
- package/plugins/qa-changes/skills/qa-changes/commands/qa-changes.md +8 -0
- package/plugins/release-notes/.claude-plugin/plugin.json +19 -0
- package/plugins/release-notes/.codex-plugin/plugin.json +19 -0
- package/plugins/release-notes/skills/release-notes/README.md +24 -0
- package/plugins/release-notes/skills/release-notes/SKILL.md +19 -0
- package/plugins/release-notes/skills/release-notes/commands/release-notes.md +8 -0
- package/plugins/vulnerability-remediation/.claude-plugin/plugin.json +19 -0
- package/plugins/vulnerability-remediation/.codex-plugin/plugin.json +19 -0
- package/plugins/vulnerability-remediation/skills/github/.claude-plugin/plugin.json +19 -0
- package/plugins/vulnerability-remediation/skills/github/.codex-plugin/plugin.json +19 -0
- package/plugins/vulnerability-remediation/skills/github/.plugin/plugin.json +19 -0
- package/plugins/vulnerability-remediation/skills/github/README.md +42 -0
- package/plugins/vulnerability-remediation/skills/github/SKILL.md +107 -0
- package/plugins/vulnerability-remediation/skills/github/references/windows.md +48 -0
- package/plugins/vulnerability-remediation/skills/github/scripts/agent_conversation.py +143 -0
- package/plugins/vulnerability-remediation/skills/github/scripts/github_client.py +230 -0
- package/plugins/vulnerability-remediation/skills/security/.claude-plugin/plugin.json +18 -0
- package/plugins/vulnerability-remediation/skills/security/.codex-plugin/plugin.json +18 -0
- package/plugins/vulnerability-remediation/skills/security/.plugin/plugin.json +18 -0
- package/plugins/vulnerability-remediation/skills/security/README.md +38 -0
- package/plugins/vulnerability-remediation/skills/security/SKILL.md +33 -0
- package/pyproject.toml +2 -2
- package/python/openhands_extensions/_version.py +1 -1
- package/skills/add-javadoc/.claude-plugin/plugin.json +18 -0
- package/skills/add-javadoc/.codex-plugin/plugin.json +18 -0
- package/skills/add-skill/.claude-plugin/plugin.json +18 -0
- package/skills/add-skill/.codex-plugin/plugin.json +18 -0
- package/skills/agent-canvas-environment/.claude-plugin/plugin.json +19 -0
- package/skills/agent-canvas-environment/.codex-plugin/plugin.json +19 -0
- package/skills/agent-creator/.claude-plugin/plugin.json +20 -0
- package/skills/agent-creator/.codex-plugin/plugin.json +20 -0
- package/skills/agent-memory/.claude-plugin/plugin.json +18 -0
- package/skills/agent-memory/.codex-plugin/plugin.json +18 -0
- package/skills/agent-sdk-builder/.claude-plugin/plugin.json +18 -0
- package/skills/agent-sdk-builder/.codex-plugin/plugin.json +18 -0
- package/skills/azure-devops/.claude-plugin/plugin.json +18 -0
- package/skills/azure-devops/.codex-plugin/plugin.json +18 -0
- package/skills/bitbucket/.claude-plugin/plugin.json +17 -0
- package/skills/bitbucket/.codex-plugin/plugin.json +17 -0
- package/skills/bitbucket-cloud/.claude-plugin/plugin.json +18 -0
- package/skills/bitbucket-cloud/.codex-plugin/plugin.json +18 -0
- package/skills/bitbucket-data-center/.claude-plugin/plugin.json +19 -0
- package/skills/bitbucket-data-center/.codex-plugin/plugin.json +19 -0
- package/skills/code-review/.claude-plugin/plugin.json +19 -0
- package/skills/code-review/.codex-plugin/plugin.json +19 -0
- package/skills/code-simplifier/.claude-plugin/plugin.json +21 -0
- package/skills/code-simplifier/.codex-plugin/plugin.json +21 -0
- package/skills/datadog/.claude-plugin/plugin.json +19 -0
- package/skills/datadog/.codex-plugin/plugin.json +19 -0
- package/skills/deno/.claude-plugin/plugin.json +18 -0
- package/skills/deno/.codex-plugin/plugin.json +18 -0
- package/skills/discord/.claude-plugin/plugin.json +18 -0
- package/skills/discord/.codex-plugin/plugin.json +18 -0
- package/skills/docker/.claude-plugin/plugin.json +17 -0
- package/skills/docker/.codex-plugin/plugin.json +17 -0
- package/skills/evidence-based-citations/.claude-plugin/plugin.json +20 -0
- package/skills/evidence-based-citations/.codex-plugin/plugin.json +20 -0
- package/skills/flarglebargle/.claude-plugin/plugin.json +16 -0
- package/skills/flarglebargle/.codex-plugin/plugin.json +16 -0
- package/skills/frontend-design/.claude-plugin/plugin.json +21 -0
- package/skills/frontend-design/.codex-plugin/plugin.json +21 -0
- package/skills/github/.claude-plugin/plugin.json +19 -0
- package/skills/github/.codex-plugin/plugin.json +19 -0
- package/skills/github/scripts/agent_conversation.py +143 -0
- package/skills/github/scripts/github_client.py +230 -0
- package/skills/github-actions/.claude-plugin/plugin.json +19 -0
- package/skills/github-actions/.codex-plugin/plugin.json +19 -0
- package/skills/github-agents-md-maintainer/.claude-plugin/plugin.json +19 -0
- package/skills/github-agents-md-maintainer/.codex-plugin/plugin.json +19 -0
- package/skills/github-agents-md-maintainer/SKILL.md +7 -1
- package/skills/github-agents-md-maintainer/scripts/github_client.py +230 -0
- package/skills/github-agents-md-maintainer/scripts/main.py +4 -40
- package/skills/github-delivery-watchdog/.claude-plugin/plugin.json +9 -0
- package/skills/github-delivery-watchdog/.codex-plugin/plugin.json +9 -0
- package/skills/github-delivery-watchdog/.plugin/plugin.json +9 -0
- package/skills/github-delivery-watchdog/README.md +10 -0
- package/skills/github-delivery-watchdog/SKILL.md +35 -0
- package/skills/github-delivery-watchdog/commands/github-delivery-watchdog.md +8 -0
- package/skills/github-delivery-watchdog/scripts/github_client.py +230 -0
- package/skills/github-delivery-watchdog/scripts/worker.py +96 -0
- package/skills/github-issue-to-pr/.claude-plugin/plugin.json +19 -0
- package/skills/github-issue-to-pr/.codex-plugin/plugin.json +19 -0
- package/skills/github-issue-to-pr/SKILL.md +15 -1
- package/skills/github-issue-to-pr/scripts/agent_conversation.py +143 -0
- package/skills/github-issue-to-pr/scripts/github_client.py +230 -0
- package/skills/github-issue-to-pr/scripts/main.py +19 -50
- package/skills/github-issue-to-pr/scripts/worker.py +172 -0
- package/skills/github-issue-triage/.claude-plugin/plugin.json +9 -0
- package/skills/github-issue-triage/.codex-plugin/plugin.json +9 -0
- package/skills/github-issue-triage/.plugin/plugin.json +9 -0
- package/skills/github-issue-triage/README.md +9 -0
- package/skills/github-issue-triage/SKILL.md +34 -0
- package/skills/github-issue-triage/commands/github-issue-triage.md +8 -0
- package/skills/github-issue-triage/scripts/agent_conversation.py +143 -0
- package/skills/github-issue-triage/scripts/github_client.py +230 -0
- package/skills/github-issue-triage/scripts/worker.py +106 -0
- package/skills/github-pr-review/.claude-plugin/plugin.json +18 -0
- package/skills/github-pr-review/.codex-plugin/plugin.json +18 -0
- package/skills/github-pr-reviewer/.claude-plugin/plugin.json +20 -0
- package/skills/github-pr-reviewer/.codex-plugin/plugin.json +20 -0
- package/skills/github-pr-reviewer/SKILL.md +15 -1
- package/skills/github-pr-reviewer/scripts/agent_conversation.py +143 -0
- package/skills/github-pr-reviewer/scripts/github_client.py +230 -0
- package/skills/github-pr-reviewer/scripts/main.py +23 -49
- package/skills/github-pr-reviewer/scripts/worker.py +94 -0
- package/skills/github-repo-monitor/.claude-plugin/plugin.json +22 -0
- package/skills/github-repo-monitor/.codex-plugin/plugin.json +22 -0
- package/skills/github-repo-monitor/SKILL.md +7 -1
- package/skills/github-repo-monitor/scripts/github_client.py +230 -0
- package/skills/github-repo-monitor/scripts/main.py +4 -46
- package/skills/gitlab/.claude-plugin/plugin.json +17 -0
- package/skills/gitlab/.codex-plugin/plugin.json +17 -0
- package/skills/gitlab-issue-to-mr/.claude-plugin/plugin.json +19 -0
- package/skills/gitlab-issue-to-mr/.codex-plugin/plugin.json +19 -0
- package/skills/gitlab-issue-to-mr/.plugin/plugin.json +19 -0
- package/skills/gitlab-issue-to-mr/README.md +92 -0
- package/skills/gitlab-issue-to-mr/SKILL.md +408 -0
- package/skills/gitlab-issue-to-mr/commands/issue-to-mr-setup.md +8 -0
- package/skills/gitlab-issue-to-mr/references/state-schema.md +140 -0
- package/skills/gitlab-issue-to-mr/scripts/main.py +1448 -0
- package/skills/incident-retrospective/.claude-plugin/plugin.json +21 -0
- package/skills/incident-retrospective/.codex-plugin/plugin.json +21 -0
- package/skills/index.js +52 -6
- package/skills/iterate/.claude-plugin/plugin.json +13 -0
- package/skills/iterate/.codex-plugin/plugin.json +13 -0
- package/skills/jira-issue-to-pr/.claude-plugin/plugin.json +19 -0
- package/skills/jira-issue-to-pr/.codex-plugin/plugin.json +19 -0
- package/skills/jupyter/.claude-plugin/plugin.json +18 -0
- package/skills/jupyter/.codex-plugin/plugin.json +18 -0
- package/skills/kubernetes/.claude-plugin/plugin.json +18 -0
- package/skills/kubernetes/.codex-plugin/plugin.json +18 -0
- package/skills/learn-from-code-review/.claude-plugin/plugin.json +19 -0
- package/skills/learn-from-code-review/.codex-plugin/plugin.json +19 -0
- package/skills/linear/.claude-plugin/plugin.json +19 -0
- package/skills/linear/.codex-plugin/plugin.json +19 -0
- package/skills/linear-triage/.claude-plugin/plugin.json +21 -0
- package/skills/linear-triage/.codex-plugin/plugin.json +21 -0
- package/skills/news-digest/.claude-plugin/plugin.json +19 -0
- package/skills/news-digest/.codex-plugin/plugin.json +19 -0
- package/skills/notion/.claude-plugin/plugin.json +17 -0
- package/skills/notion/.codex-plugin/plugin.json +17 -0
- package/skills/npm/.claude-plugin/plugin.json +17 -0
- package/skills/npm/.codex-plugin/plugin.json +17 -0
- package/skills/openhands-api/.claude-plugin/plugin.json +22 -0
- package/skills/openhands-api/.codex-plugin/plugin.json +22 -0
- package/skills/openhands-automation/.claude-plugin/plugin.json +19 -0
- package/skills/openhands-automation/.codex-plugin/plugin.json +19 -0
- package/skills/openhands-automation/README.md +1 -1
- package/skills/openhands-automation/SKILL.md +18 -8
- package/skills/openhands-enterprise-troubleshooting/.claude-plugin/plugin.json +20 -0
- package/skills/openhands-enterprise-troubleshooting/.codex-plugin/plugin.json +20 -0
- package/skills/openhands-enterprise-troubleshooting/.plugin/plugin.json +20 -0
- package/skills/openhands-enterprise-troubleshooting/README.md +79 -0
- package/skills/openhands-enterprise-troubleshooting/SKILL.md +339 -0
- package/skills/openhands-enterprise-troubleshooting/references/diagnostics.md +698 -0
- package/skills/openhands-enterprise-troubleshooting/references/support-bundle-analysis.md +570 -0
- package/skills/openhands-enterprise-troubleshooting/scripts/bundle_triage.py +532 -0
- package/skills/openhands-sdk/.claude-plugin/plugin.json +20 -0
- package/skills/openhands-sdk/.codex-plugin/plugin.json +20 -0
- package/skills/openhands-sdk/SKILL.md +2 -0
- package/skills/pdflatex/.claude-plugin/plugin.json +18 -0
- package/skills/pdflatex/.codex-plugin/plugin.json +18 -0
- package/skills/plain-english-content/.claude-plugin/plugin.json +15 -0
- package/skills/plain-english-content/.codex-plugin/plugin.json +15 -0
- package/skills/prd/.claude-plugin/plugin.json +19 -0
- package/skills/prd/.codex-plugin/plugin.json +19 -0
- package/skills/research-brief/.claude-plugin/plugin.json +20 -0
- package/skills/research-brief/.codex-plugin/plugin.json +20 -0
- package/skills/security/.claude-plugin/plugin.json +18 -0
- package/skills/security/.codex-plugin/plugin.json +18 -0
- package/skills/skill-creator/.claude-plugin/plugin.json +17 -0
- package/skills/skill-creator/.codex-plugin/plugin.json +17 -0
- package/skills/slack-channel-monitor/.claude-plugin/plugin.json +21 -0
- package/skills/slack-channel-monitor/.codex-plugin/plugin.json +21 -0
- package/skills/slack-standup-digest/.claude-plugin/plugin.json +21 -0
- package/skills/slack-standup-digest/.codex-plugin/plugin.json +21 -0
- package/skills/spark-version-upgrade/.claude-plugin/plugin.json +20 -0
- package/skills/spark-version-upgrade/.codex-plugin/plugin.json +20 -0
- package/skills/ssh/.claude-plugin/plugin.json +18 -0
- package/skills/ssh/.codex-plugin/plugin.json +18 -0
- package/skills/swift-linux/.claude-plugin/plugin.json +17 -0
- package/skills/swift-linux/.codex-plugin/plugin.json +17 -0
- package/skills/technical-writing/.claude-plugin/plugin.json +15 -0
- package/skills/technical-writing/.codex-plugin/plugin.json +15 -0
- package/skills/theme-factory/.claude-plugin/plugin.json +19 -0
- package/skills/theme-factory/.codex-plugin/plugin.json +19 -0
- package/skills/ticket-to-code-change/.claude-plugin/plugin.json +21 -0
- package/skills/ticket-to-code-change/.codex-plugin/plugin.json +21 -0
- package/skills/upstream-fork-sync/.claude-plugin/plugin.json +21 -0
- package/skills/upstream-fork-sync/.codex-plugin/plugin.json +21 -0
- package/skills/uv/.claude-plugin/plugin.json +18 -0
- package/skills/uv/.codex-plugin/plugin.json +18 -0
- package/skills/vercel/.claude-plugin/plugin.json +18 -0
- package/skills/vercel/.codex-plugin/plugin.json +18 -0
- package/tests/fixtures/automations/capabilities.json +6 -3
- package/tests/fixtures/automations/github-pr-reviewer.json +64 -43
- package/tests/github_automation_helpers.py +31 -0
- package/tests/test_agent_conversation_dispatch.py +180 -0
- package/tests/test_automation_setup.py +3 -3
- package/tests/test_github_automation_foundation.py +73 -0
- package/tests/test_github_developer_delivery.py +150 -0
- package/tests/test_github_reviewer_delivery.py +110 -0
- package/tests/test_github_skill_installation.py +63 -0
- package/tests/test_github_triage_delivery.py +90 -0
- package/tests/test_github_watchdog_delivery.py +233 -0
- package/tests/test_gitlab_issue_to_mr.py +823 -0
- package/.pr/custom-automation-event-trigger.png +0 -0
- package/.pr/custom-automation-plugin-fields.png +0 -0
- package/.pr/custom-automation-prompt-review.png +0 -0
- package/.pr/custom-automation-prompt-scheduled.png +0 -0
- package/.pr/custom-automation-upload-fields.png +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Windows Notes for GitHub Commands
|
|
2
|
+
|
|
3
|
+
Use these PowerShell forms when running this skill's GitHub commands natively on Windows.
|
|
4
|
+
|
|
5
|
+
## Environment Variables
|
|
6
|
+
|
|
7
|
+
PowerShell environment variables use `$env:NAME`:
|
|
8
|
+
|
|
9
|
+
```powershell
|
|
10
|
+
git remote set-url origin "https://$($env:GITHUB_TOKEN)@github.com/username/repo.git"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Chained Git Commands
|
|
14
|
+
|
|
15
|
+
If the installed shell does not support `&&`, run the commands separately and stop if one fails:
|
|
16
|
+
|
|
17
|
+
```powershell
|
|
18
|
+
git remote -v
|
|
19
|
+
git branch
|
|
20
|
+
git checkout -b create-widget
|
|
21
|
+
git add .
|
|
22
|
+
git commit -m "Create widget"
|
|
23
|
+
git push -u origin create-widget
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## GraphQL Requests with gh
|
|
27
|
+
|
|
28
|
+
For multi-line GraphQL queries, use a PowerShell here-string and pass it to `gh api`.
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
$query = @'
|
|
32
|
+
{
|
|
33
|
+
repository(owner: "<OWNER>", name: "<REPO>") {
|
|
34
|
+
pullRequest(number: <PR_NUMBER>) {
|
|
35
|
+
reviewThreads(first: 20) {
|
|
36
|
+
nodes { id isResolved }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
'@
|
|
42
|
+
|
|
43
|
+
gh api graphql -f query="$query"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Redirects
|
|
47
|
+
|
|
48
|
+
Replace POSIX redirects such as `2>/dev/null` with PowerShell redirects such as `2>$null`.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Idempotently deliver automation work to profile-backed conversations."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from urllib.error import HTTPError
|
|
6
|
+
from urllib.request import Request, urlopen
|
|
7
|
+
from uuid import NAMESPACE_URL, UUID, uuid5
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
from openhands.sdk import RemoteConversation
|
|
11
|
+
from openhands.sdk.conversation.request import (
|
|
12
|
+
SendMessageRequest,
|
|
13
|
+
StartConversationRequest,
|
|
14
|
+
)
|
|
15
|
+
from openhands.sdk.conversation.state import ConversationExecutionStatus
|
|
16
|
+
from openhands.sdk.llm.message import TextContent
|
|
17
|
+
from openhands.sdk.workspace import LocalWorkspace, RemoteWorkspace
|
|
18
|
+
|
|
19
|
+
_CONVERSATION_KEY_PREFIX = "agent-conversation-"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _register_tools() -> None:
|
|
23
|
+
"""Register tool models needed to deserialize an attached agent."""
|
|
24
|
+
from openhands.tools import register_default_tools
|
|
25
|
+
|
|
26
|
+
register_default_tools()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _kv_request(key: str, method: str, value: dict | None = None) -> dict | None:
|
|
30
|
+
base_url = os.environ.get("AUTOMATION_API_URL", "").rstrip("/")
|
|
31
|
+
token = os.environ.get("AUTOMATION_KV_TOKEN", "")
|
|
32
|
+
if not base_url or not token:
|
|
33
|
+
raise RuntimeError("Automation KV is required for agent conversation dispatch")
|
|
34
|
+
request = Request(
|
|
35
|
+
f"{base_url}/v1/kv/{key}",
|
|
36
|
+
data=json.dumps(value).encode() if value is not None else None,
|
|
37
|
+
headers={
|
|
38
|
+
"Authorization": f"Bearer {token}",
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
},
|
|
41
|
+
method=method,
|
|
42
|
+
)
|
|
43
|
+
try:
|
|
44
|
+
with urlopen(request, timeout=90) as response:
|
|
45
|
+
body = json.load(response)
|
|
46
|
+
except HTTPError as exc:
|
|
47
|
+
if method == "GET" and exc.code == 404:
|
|
48
|
+
return None
|
|
49
|
+
raise
|
|
50
|
+
return body.get("value") if method == "GET" else body
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AgentConversationDispatcher:
|
|
54
|
+
"""Deliver one revision at a time to a stable conversation for each subject."""
|
|
55
|
+
|
|
56
|
+
def __init__(self) -> None:
|
|
57
|
+
self.agent_url = os.environ["AGENT_SERVER_URL"]
|
|
58
|
+
self.api_key = os.environ["SESSION_API_KEY"]
|
|
59
|
+
self.profile_id = UUID(os.environ["AUTOMATION_AGENT_PROFILE_ID"])
|
|
60
|
+
payload = json.loads(os.environ["AUTOMATION_EVENT_PAYLOAD"])
|
|
61
|
+
self.automation_id = str(payload["automation_id"])
|
|
62
|
+
self._workspace: RemoteWorkspace | None = None
|
|
63
|
+
|
|
64
|
+
def __enter__(self):
|
|
65
|
+
_register_tools()
|
|
66
|
+
self._workspace = RemoteWorkspace(
|
|
67
|
+
host=self.agent_url,
|
|
68
|
+
api_key=self.api_key,
|
|
69
|
+
working_dir=os.environ.get("WORKSPACE_BASE", "/workspace"),
|
|
70
|
+
)
|
|
71
|
+
self._workspace.__enter__()
|
|
72
|
+
return self
|
|
73
|
+
|
|
74
|
+
def __exit__(self, *args):
|
|
75
|
+
assert self._workspace is not None
|
|
76
|
+
return self._workspace.__exit__(*args)
|
|
77
|
+
|
|
78
|
+
def deliver(self, subject: str, delivery: str, prompt: str) -> dict[str, str]:
|
|
79
|
+
conversation_id = uuid5(NAMESPACE_URL, f"{self.automation_id}:{subject}")
|
|
80
|
+
state_key = f"{_CONVERSATION_KEY_PREFIX}{conversation_id}"
|
|
81
|
+
record = _kv_request(state_key, "GET") or {}
|
|
82
|
+
if self._workspace is None:
|
|
83
|
+
raise RuntimeError("AgentConversationDispatcher must be used as a context")
|
|
84
|
+
|
|
85
|
+
same_delivery = record.get("delivery") == delivery
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
conversation = RemoteConversation.attach(
|
|
89
|
+
self._workspace, conversation_id, visualizer=None
|
|
90
|
+
)
|
|
91
|
+
disposition = "resumed"
|
|
92
|
+
except httpx.HTTPStatusError as exc:
|
|
93
|
+
if exc.response.status_code != 404:
|
|
94
|
+
raise
|
|
95
|
+
conversation = RemoteConversation.create(
|
|
96
|
+
self._workspace,
|
|
97
|
+
StartConversationRequest(
|
|
98
|
+
workspace=LocalWorkspace(working_dir="/workspace"),
|
|
99
|
+
conversation_id=conversation_id,
|
|
100
|
+
agent_profile_id=self.profile_id,
|
|
101
|
+
initial_message=SendMessageRequest(
|
|
102
|
+
content=[TextContent(text=prompt)], run=True
|
|
103
|
+
),
|
|
104
|
+
),
|
|
105
|
+
visualizer=None,
|
|
106
|
+
)
|
|
107
|
+
disposition = "created"
|
|
108
|
+
try:
|
|
109
|
+
if disposition == "resumed":
|
|
110
|
+
if same_delivery:
|
|
111
|
+
if conversation.state.execution_status in (
|
|
112
|
+
ConversationExecutionStatus.IDLE,
|
|
113
|
+
ConversationExecutionStatus.RUNNING,
|
|
114
|
+
ConversationExecutionStatus.PAUSED,
|
|
115
|
+
):
|
|
116
|
+
conversation.run(blocking=False)
|
|
117
|
+
else:
|
|
118
|
+
disposition = "deduplicated"
|
|
119
|
+
else:
|
|
120
|
+
conversation.send_message(prompt)
|
|
121
|
+
conversation.run(blocking=False)
|
|
122
|
+
finally:
|
|
123
|
+
conversation.close()
|
|
124
|
+
|
|
125
|
+
if disposition == "deduplicated":
|
|
126
|
+
return {
|
|
127
|
+
"disposition": disposition,
|
|
128
|
+
"conversation_id": str(conversation_id),
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
_kv_request(
|
|
132
|
+
state_key,
|
|
133
|
+
"PUT",
|
|
134
|
+
{
|
|
135
|
+
"subject": subject,
|
|
136
|
+
"conversation_id": str(conversation_id),
|
|
137
|
+
"delivery": delivery,
|
|
138
|
+
},
|
|
139
|
+
)
|
|
140
|
+
return {
|
|
141
|
+
"disposition": disposition,
|
|
142
|
+
"conversation_id": str(conversation_id),
|
|
143
|
+
}
|
|
@@ -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
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "security",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Security best practices for secure coding, authentication, authorization, and data protection. Use when developing features that handle sensitive data, user authentication, or require security review.",
|
|
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
|
+
"security",
|
|
14
|
+
"authentication",
|
|
15
|
+
"authorization",
|
|
16
|
+
"encryption"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "security",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Security best practices for secure coding, authentication, authorization, and data protection. Use when developing features that handle sensitive data, user authentication, or require security review.",
|
|
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
|
+
"security",
|
|
14
|
+
"authentication",
|
|
15
|
+
"authorization",
|
|
16
|
+
"encryption"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "security",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Security best practices for secure coding, authentication, authorization, and data protection. Use when developing features that handle sensitive data, user authentication, or require security review.",
|
|
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
|
+
"security",
|
|
14
|
+
"authentication",
|
|
15
|
+
"authorization",
|
|
16
|
+
"encryption"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
Security best practices for secure coding, authentication, authorization, and data protection. Use when developing features that handle sensitive data, user authentication, or require security review.
|
|
4
|
+
|
|
5
|
+
## Triggers
|
|
6
|
+
|
|
7
|
+
This skill is activated by the following keywords:
|
|
8
|
+
|
|
9
|
+
- `security`
|
|
10
|
+
- `vulnerability`
|
|
11
|
+
- `authentication`
|
|
12
|
+
- `authorization`
|
|
13
|
+
- `permissions`
|
|
14
|
+
|
|
15
|
+
## Details
|
|
16
|
+
|
|
17
|
+
This document provides guidance on security best practices
|
|
18
|
+
|
|
19
|
+
You should always be considering security implications when developing.
|
|
20
|
+
You should always complete the task requested. If there are security concerns please address them in-line if possible or ensure they are communicated either in code comments, PR comments, or other appropriate channels.
|
|
21
|
+
|
|
22
|
+
## Core Security Principles
|
|
23
|
+
- Always use secure communication protocols (HTTPS, SSH, etc.)
|
|
24
|
+
- Never store sensitive data (passwords, tokens, keys) in code or version control unless given explicit permission.
|
|
25
|
+
- Apply the principle of least privilege
|
|
26
|
+
- Validate and sanitize all user inputs
|
|
27
|
+
|
|
28
|
+
## Common Security Checks
|
|
29
|
+
- Ensure proper authentication and authorization mechanisms
|
|
30
|
+
- Verify secure session management
|
|
31
|
+
- Confirm secure storage of sensitive data
|
|
32
|
+
- Validate secure configuration of services and APIs
|
|
33
|
+
|
|
34
|
+
## Error Handling
|
|
35
|
+
- Never expose sensitive information in error messages
|
|
36
|
+
- Log security events appropriately
|
|
37
|
+
- Implement proper exception handling
|
|
38
|
+
- Use secure error reporting mechanisms
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security
|
|
3
|
+
description: Security best practices for secure coding, authentication, authorization, and data protection. Use when developing features that handle sensitive data, user authentication, or require security review.
|
|
4
|
+
triggers:
|
|
5
|
+
- security
|
|
6
|
+
- vulnerability
|
|
7
|
+
- authentication
|
|
8
|
+
- authorization
|
|
9
|
+
- permissions
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
This document provides guidance on security best practices
|
|
13
|
+
|
|
14
|
+
You should always be considering security implications when developing.
|
|
15
|
+
You should always complete the task requested. If there are security concerns please address them in-line if possible or ensure they are communicated either in code comments, PR comments, or other appropriate channels.
|
|
16
|
+
|
|
17
|
+
## Core Security Principles
|
|
18
|
+
- Always use secure communication protocols (HTTPS, SSH, etc.)
|
|
19
|
+
- Never store sensitive data (passwords, tokens, keys) in code or version control unless given explicit permission.
|
|
20
|
+
- Apply the principle of least privilege
|
|
21
|
+
- Validate and sanitize all user inputs
|
|
22
|
+
|
|
23
|
+
## Common Security Checks
|
|
24
|
+
- Ensure proper authentication and authorization mechanisms
|
|
25
|
+
- Verify secure session management
|
|
26
|
+
- Confirm secure storage of sensitive data
|
|
27
|
+
- Validate secure configuration of services and APIs
|
|
28
|
+
|
|
29
|
+
## Error Handling
|
|
30
|
+
- Never expose sensitive information in error messages
|
|
31
|
+
- Log security events appropriately
|
|
32
|
+
- Implement proper exception handling
|
|
33
|
+
- Use secure error reporting mechanisms
|
package/pyproject.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "openhands-extensions"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.22.0"
|
|
4
4
|
description = "OpenHands extensions, plugins, and skills (Python bindings for the integration catalog)"
|
|
5
5
|
requires-python = ">=3.12"
|
|
6
6
|
dependencies = [
|
|
@@ -28,5 +28,5 @@ test = [
|
|
|
28
28
|
]
|
|
29
29
|
|
|
30
30
|
[tool.pytest.ini_options]
|
|
31
|
-
pythonpath = ["python"]
|
|
31
|
+
pythonpath = ["python", "skills/github/scripts"]
|
|
32
32
|
testpaths = ["tests"]
|
|
@@ -18,7 +18,7 @@ from importlib.metadata import PackageNotFoundError, version
|
|
|
18
18
|
#: Kept in lock-step with pyproject.toml/package.json by the version test.
|
|
19
19
|
#: release-please only rewrites a semver found on the annotated line itself, so
|
|
20
20
|
#: the annotation must stay on the assignment; on its own line it is a no-op.
|
|
21
|
-
_FALLBACK_VERSION = "0.
|
|
21
|
+
_FALLBACK_VERSION = "0.22.0" # x-release-please-version
|
|
22
22
|
|
|
23
23
|
try:
|
|
24
24
|
__version__: str = version("openhands-extensions")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "add-javadoc",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Add comprehensive JavaDoc documentation to Java classes and methods. Use when documenting Java code, adding API documentation, or improving code documentation.",
|
|
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
|
+
"javadoc",
|
|
14
|
+
"java",
|
|
15
|
+
"documentation",
|
|
16
|
+
"api-docs"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "add-javadoc",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Add comprehensive JavaDoc documentation to Java classes and methods. Use when documenting Java code, adding API documentation, or improving code documentation.",
|
|
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
|
+
"javadoc",
|
|
14
|
+
"java",
|
|
15
|
+
"documentation",
|
|
16
|
+
"api-docs"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "add-skill",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Add (import) an OpenHands skill from a GitHub repository into the current workspace.",
|
|
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
|
+
"skill",
|
|
14
|
+
"import",
|
|
15
|
+
"github",
|
|
16
|
+
"sparse-checkout"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "add-skill",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Add (import) an OpenHands skill from a GitHub repository into the current workspace.",
|
|
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
|
+
"skill",
|
|
14
|
+
"import",
|
|
15
|
+
"github",
|
|
16
|
+
"sparse-checkout"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-canvas-environment",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Work effectively inside a local Agent Canvas environment, including local agent-server auth, frontend/backend port discovery, safe workspace hygiene, and local conversation delegation.",
|
|
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
|
+
"agent-canvas",
|
|
14
|
+
"openhands",
|
|
15
|
+
"local",
|
|
16
|
+
"conversation",
|
|
17
|
+
"delegation"
|
|
18
|
+
]
|
|
19
|
+
}
|