@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.
- package/.agents/skills/custom-codereview-guide.md +25 -0
- package/.github/pull_request_template.md +38 -0
- package/.github/release.yml +14 -0
- package/.github/workflows/check-extensions.yml +72 -0
- package/.github/workflows/npm-publish.yml +89 -0
- package/.github/workflows/pr.yml +30 -0
- package/.github/workflows/release.yml +24 -0
- package/.github/workflows/tests.yml +25 -0
- package/.github/workflows/vulnerability-scan.yml +87 -0
- package/.release-please-manifest.json +3 -0
- package/AGENTS.md +132 -0
- package/README.md +10 -0
- package/analysis_results.md +162 -0
- package/marketplaces/large-codebase.json +66 -0
- package/marketplaces/openhands-extensions.json +682 -0
- package/package.json +4 -10
- package/plugins/README.md +30 -0
- package/plugins/city-weather/.plugin/plugin.json +13 -0
- package/plugins/city-weather/README.md +145 -0
- package/plugins/city-weather/commands/now.md +56 -0
- package/plugins/cobol-modernization/.plugin/plugin.json +19 -0
- package/plugins/cobol-modernization/README.md +201 -0
- package/plugins/cobol-modernization/references/troubleshooting.md +18 -0
- package/plugins/cobol-modernization/skills/build-setup/SKILL.md +78 -0
- package/plugins/cobol-modernization/skills/build-setup/scripts/install-gnucobol.sh +32 -0
- package/plugins/cobol-modernization/skills/cobol-modernization-overview/SKILL.md +113 -0
- package/plugins/cobol-modernization/skills/mainfraime-removal/SKILL.md +62 -0
- package/plugins/cobol-modernization/skills/mainfraime-removal/references/cics-transformation-examples.md +45 -0
- package/plugins/cobol-modernization/skills/mainframe-planning/SKILL.md +78 -0
- package/plugins/cobol-modernization/skills/to-java-migration/SKILL.md +59 -0
- package/plugins/cobol-modernization/skills/to-java-migration/references/cobol-to-java-example.md +58 -0
- package/plugins/cobol-modernization/skills/to-java-migration/references/datatype-mappings.md +19 -0
- package/plugins/issue-duplicate-checker/.plugin/plugin.json +13 -0
- package/plugins/issue-duplicate-checker/README.md +51 -0
- package/plugins/issue-duplicate-checker/action.yml +349 -0
- package/plugins/issue-duplicate-checker/scripts/auto_close_duplicate_issues.py +569 -0
- package/plugins/issue-duplicate-checker/scripts/issue_duplicate_check_openhands.py +681 -0
- package/plugins/issue-duplicate-checker/scripts/post_duplicate_notice.js +220 -0
- package/plugins/issue-duplicate-checker/scripts/remove_duplicate_candidate_label.js +27 -0
- package/plugins/magic-test/.plugin/plugin.json +13 -0
- package/plugins/magic-test/skills/magic-word/SKILL.md +33 -0
- package/plugins/migration-scoring/.plugin/plugin.json +19 -0
- package/plugins/migration-scoring/README.md +244 -0
- package/plugins/migration-scoring/skills/migration-mapping/SKILL.md +72 -0
- package/plugins/migration-scoring/skills/migration-report/SKILL.md +118 -0
- package/plugins/migration-scoring/skills/migration-scoring-overview/SKILL.md +126 -0
- package/plugins/migration-scoring/skills/score-quality/SKILL.md +54 -0
- package/plugins/migration-scoring/skills/score-quality/references/scoring-criteria.md +30 -0
- package/plugins/migration-scoring/skills/score-style/SKILL.md +106 -0
- package/plugins/onboarding/.plugin/plugin.json +20 -0
- package/plugins/onboarding/README.md +30 -0
- package/plugins/onboarding/references/criteria.md +144 -0
- package/plugins/onboarding/skills/agent-readiness-report/README.md +23 -0
- package/plugins/onboarding/skills/agent-readiness-report/SKILL.md +122 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_agent_instructions.sh +88 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_build_env.sh +114 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_feedback_loops.sh +133 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_policy.sh +113 -0
- package/plugins/onboarding/skills/agent-readiness-report/scripts/scan_workflows.sh +127 -0
- package/plugins/onboarding/skills/improve-agent-readiness/README.md +19 -0
- package/plugins/onboarding/skills/improve-agent-readiness/SKILL.md +167 -0
- package/plugins/onboarding/skills/setup-agents-md/README.md +15 -0
- package/plugins/onboarding/skills/setup-agents-md/SKILL.md +150 -0
- package/plugins/onboarding/skills/setup-openhands/README.md +20 -0
- package/plugins/onboarding/skills/setup-openhands/SKILL.md +56 -0
- package/plugins/onboarding/skills/setup-pr-review/README.md +23 -0
- package/plugins/onboarding/skills/setup-pr-review/SKILL.md +72 -0
- package/plugins/openhands/.plugin/plugin.json +13 -0
- package/plugins/openhands/README.md +52 -0
- package/plugins/openhands/SKILL.md +61 -0
- package/plugins/openhands/commands/create.md +55 -0
- package/plugins/openhands/commands/openhands-cloud.md +8 -0
- package/plugins/openhands/scripts/run.sh +69 -0
- package/plugins/pr-review/.plugin/plugin.json +13 -0
- package/plugins/pr-review/README.md +393 -0
- package/plugins/pr-review/action.yml +298 -0
- package/plugins/pr-review/scripts/agent_script.py +1282 -0
- package/plugins/pr-review/scripts/evaluate_review.py +655 -0
- package/plugins/pr-review/scripts/prompt.py +260 -0
- package/plugins/pr-review/workflows/pr-review-by-openhands.yml +51 -0
- package/plugins/pr-review/workflows/pr-review-evaluation.yml +85 -0
- package/plugins/qa-changes/.plugin/plugin.json +11 -0
- package/plugins/qa-changes/README.md +185 -0
- package/plugins/qa-changes/action.yml +181 -0
- package/plugins/qa-changes/scripts/agent_script.py +406 -0
- package/plugins/qa-changes/scripts/evaluate_qa_changes.py +385 -0
- package/plugins/qa-changes/scripts/prompt.py +174 -0
- package/plugins/qa-changes/workflows/qa-changes-by-openhands.yml +50 -0
- package/plugins/qa-changes/workflows/qa-changes-evaluation.yml +85 -0
- package/plugins/release-notes/.plugin/plugin.json +19 -0
- package/plugins/release-notes/README.md +283 -0
- package/plugins/release-notes/SKILL.md +83 -0
- package/plugins/release-notes/action.yml +117 -0
- package/plugins/release-notes/commands/release-notes.md +8 -0
- package/plugins/release-notes/scripts/agent_script.py +292 -0
- package/plugins/release-notes/scripts/generate_release_notes.py +733 -0
- package/plugins/release-notes/scripts/prompt.py +90 -0
- package/plugins/release-notes/scripts/validate_release_notes.py +328 -0
- package/plugins/release-notes/workflows/release-notes.yml +76 -0
- package/plugins/vulnerability-remediation/.plugin/plugin.json +19 -0
- package/plugins/vulnerability-remediation/README.md +217 -0
- package/plugins/vulnerability-remediation/action.yml +187 -0
- package/plugins/vulnerability-remediation/scripts/scan_and_remediate.py +561 -0
- package/plugins/vulnerability-remediation/workflows/vulnerability-scan.yml +87 -0
- package/pyproject.toml +12 -0
- package/release-please-config.json +16 -0
- package/scripts/sync_extensions.py +494 -0
- package/scripts/sync_openhands_sdk_skill.py +264 -0
- package/skills/README.md +159 -0
- package/skills/add-javadoc/.plugin/plugin.json +18 -0
- package/skills/add-javadoc/README.md +40 -0
- package/skills/add-javadoc/SKILL.md +35 -0
- package/skills/add-javadoc/references/example.md +32 -0
- package/skills/add-skill/.plugin/plugin.json +18 -0
- package/skills/add-skill/README.md +67 -0
- package/skills/add-skill/SKILL.md +47 -0
- package/skills/add-skill/scripts/fetch_skill.py +259 -0
- package/skills/agent-creator/.plugin/plugin.json +20 -0
- package/skills/agent-creator/README.md +104 -0
- package/skills/agent-creator/SKILL.md +190 -0
- package/skills/agent-creator/commands/agent-creator.md +8 -0
- package/skills/agent-creator/references/fallback.md +117 -0
- package/skills/agent-memory/.plugin/plugin.json +18 -0
- package/skills/agent-memory/README.md +35 -0
- package/skills/agent-memory/SKILL.md +30 -0
- package/skills/agent-memory/commands/remember.md +8 -0
- package/skills/agent-sdk-builder/.plugin/plugin.json +18 -0
- package/skills/agent-sdk-builder/README.md +40 -0
- package/skills/agent-sdk-builder/SKILL.md +37 -0
- package/skills/agent-sdk-builder/commands/agent-builder.md +8 -0
- package/skills/azure-devops/.plugin/plugin.json +18 -0
- package/skills/azure-devops/README.md +55 -0
- package/skills/azure-devops/SKILL.md +50 -0
- package/skills/bitbucket/.plugin/plugin.json +17 -0
- package/skills/bitbucket/README.md +50 -0
- package/skills/bitbucket/SKILL.md +45 -0
- package/skills/code-review/.plugin/plugin.json +19 -0
- package/skills/code-review/README.md +18 -0
- package/skills/code-review/SKILL.md +208 -0
- package/skills/code-review/commands/codereview-roasted.md +8 -0
- package/skills/code-review/commands/codereview.md +8 -0
- package/skills/code-review/references/risk-evaluation.md +41 -0
- package/skills/code-review/references/supply-chain-security.md +31 -0
- package/skills/code-simplifier/.plugin/plugin.json +21 -0
- package/skills/code-simplifier/README.md +30 -0
- package/skills/code-simplifier/SKILL.md +91 -0
- package/skills/code-simplifier/commands/simplify.md +8 -0
- package/skills/code-simplifier/references/code-quality-review.md +86 -0
- package/skills/code-simplifier/references/code-reuse-review.md +63 -0
- package/skills/code-simplifier/references/efficiency-review.md +81 -0
- package/skills/datadog/.plugin/plugin.json +19 -0
- package/skills/datadog/README.md +100 -0
- package/skills/datadog/SKILL.md +95 -0
- package/skills/deno/.plugin/plugin.json +18 -0
- package/skills/deno/README.md +5 -0
- package/skills/deno/SKILL.md +99 -0
- package/skills/deno/references/README.md +6 -0
- package/skills/discord/.plugin/plugin.json +18 -0
- package/skills/discord/README.md +31 -0
- package/skills/discord/SKILL.md +109 -0
- package/skills/discord/__init__.py +0 -0
- package/skills/discord/references/REFERENCE.md +78 -0
- package/skills/discord/scripts/__init__.py +0 -0
- package/skills/discord/scripts/_http.py +127 -0
- package/skills/discord/scripts/post_webhook.py +106 -0
- package/skills/discord/scripts/send_message.py +102 -0
- package/skills/docker/.plugin/plugin.json +17 -0
- package/skills/docker/README.md +34 -0
- package/skills/docker/SKILL.md +29 -0
- package/skills/evidence-based-citations/.plugin/plugin.json +20 -0
- package/skills/evidence-based-citations/README.md +31 -0
- package/skills/evidence-based-citations/SKILL.md +59 -0
- package/skills/flarglebargle/.plugin/plugin.json +16 -0
- package/skills/flarglebargle/README.md +14 -0
- package/skills/flarglebargle/SKILL.md +9 -0
- package/skills/frontend-design/.plugin/plugin.json +21 -0
- package/skills/frontend-design/LICENSE.txt +177 -0
- package/skills/frontend-design/README.md +42 -0
- package/skills/frontend-design/SKILL.md +42 -0
- package/skills/github/.plugin/plugin.json +19 -0
- package/skills/github/README.md +42 -0
- package/skills/github/SKILL.md +106 -0
- package/skills/github-pr-review/.plugin/plugin.json +18 -0
- package/skills/github-pr-review/README.md +145 -0
- package/skills/github-pr-review/SKILL.md +148 -0
- package/skills/github-pr-review/commands/github-pr-review.md +8 -0
- package/skills/github-pr-reviewer/.plugin/plugin.json +20 -0
- package/skills/github-pr-reviewer/README.md +34 -0
- package/skills/github-pr-reviewer/SKILL.md +89 -0
- package/skills/github-pr-reviewer/commands/pr-reviewer:setup.md +8 -0
- package/skills/github-repo-monitor/.plugin/plugin.json +22 -0
- package/skills/github-repo-monitor/README.md +70 -0
- package/skills/github-repo-monitor/SKILL.md +316 -0
- package/skills/github-repo-monitor/commands/github-monitor:poll.md +8 -0
- package/skills/github-repo-monitor/references/github-api.md +241 -0
- package/skills/github-repo-monitor/references/state-schema.md +160 -0
- package/skills/github-repo-monitor/scripts/main.py +915 -0
- package/skills/github-repo-monitor/tests/test_main.py +400 -0
- package/skills/gitlab/.plugin/plugin.json +17 -0
- package/skills/gitlab/README.md +37 -0
- package/skills/gitlab/SKILL.md +32 -0
- package/skills/incident-retrospective/.plugin/plugin.json +21 -0
- package/skills/incident-retrospective/README.md +34 -0
- package/skills/incident-retrospective/SKILL.md +98 -0
- package/skills/incident-retrospective/commands/incident-retro:setup.md +8 -0
- package/skills/iterate/.plugin/plugin.json +13 -0
- package/skills/iterate/README.md +25 -0
- package/skills/iterate/SKILL.md +399 -0
- package/skills/iterate/commands/babysit.md +8 -0
- package/skills/iterate/commands/iterate.md +8 -0
- package/skills/iterate/commands/verify.md +8 -0
- package/skills/iterate/references/heuristics.md +58 -0
- package/skills/iterate/references/verification.md +96 -0
- package/skills/jupyter/.plugin/plugin.json +18 -0
- package/skills/jupyter/README.md +55 -0
- package/skills/jupyter/SKILL.md +50 -0
- package/skills/kubernetes/.plugin/plugin.json +18 -0
- package/skills/kubernetes/README.md +53 -0
- package/skills/kubernetes/SKILL.md +48 -0
- package/skills/learn-from-code-review/.plugin/plugin.json +19 -0
- package/skills/learn-from-code-review/README.md +64 -0
- package/skills/learn-from-code-review/SKILL.md +186 -0
- package/skills/learn-from-code-review/commands/learn-from-reviews.md +8 -0
- package/skills/linear/.plugin/plugin.json +19 -0
- package/skills/linear/README.md +58 -0
- package/skills/linear/SKILL.md +213 -0
- package/skills/linear-triage/.plugin/plugin.json +21 -0
- package/skills/linear-triage/README.md +34 -0
- package/skills/linear-triage/SKILL.md +91 -0
- package/skills/linear-triage/commands/linear-triage:setup.md +8 -0
- package/skills/notion/.plugin/plugin.json +17 -0
- package/skills/notion/README.md +114 -0
- package/skills/notion/SKILL.md +109 -0
- package/skills/npm/.plugin/plugin.json +17 -0
- package/skills/npm/README.md +14 -0
- package/skills/npm/SKILL.md +9 -0
- package/skills/openhands-api/.plugin/plugin.json +22 -0
- package/skills/openhands-api/README.md +48 -0
- package/skills/openhands-api/SKILL.md +399 -0
- package/skills/openhands-api/references/README.md +33 -0
- package/skills/openhands-api/references/TROUBLESHOOTING.md +81 -0
- package/skills/openhands-api/references/example_prompt.md +12 -0
- package/skills/openhands-api/scripts/openhands_api.py +606 -0
- package/skills/openhands-api/scripts/openhands_api.ts +252 -0
- package/skills/openhands-automation/.plugin/plugin.json +19 -0
- package/skills/openhands-automation/README.md +89 -0
- package/skills/openhands-automation/SKILL.md +875 -0
- package/skills/openhands-automation/commands/automation:create.md +8 -0
- package/skills/openhands-automation/references/ab-testing.md +185 -0
- package/skills/openhands-automation/references/custom-automation.md +644 -0
- package/skills/openhands-sdk/.plugin/plugin.json +20 -0
- package/skills/openhands-sdk/README.md +22 -0
- package/skills/openhands-sdk/SKILL.md +229 -0
- package/skills/openhands-sdk/commands/sdk.md +8 -0
- package/skills/pdflatex/.plugin/plugin.json +18 -0
- package/skills/pdflatex/README.md +39 -0
- package/skills/pdflatex/SKILL.md +34 -0
- package/skills/prd/.plugin/plugin.json +19 -0
- package/skills/prd/README.md +28 -0
- package/skills/prd/SKILL.md +237 -0
- package/skills/prd/commands/prd.md +8 -0
- package/skills/qa-changes/README.md +18 -0
- package/skills/qa-changes/SKILL.md +229 -0
- package/skills/qa-changes/commands/qa-changes.md +8 -0
- package/skills/release-notes/README.md +24 -0
- package/skills/release-notes/SKILL.md +19 -0
- package/skills/release-notes/commands/release-notes.md +8 -0
- package/skills/research-brief/.plugin/plugin.json +20 -0
- package/skills/research-brief/README.md +34 -0
- package/skills/research-brief/SKILL.md +99 -0
- package/skills/research-brief/commands/research-brief:setup.md +8 -0
- package/skills/security/.plugin/plugin.json +18 -0
- package/skills/security/README.md +38 -0
- package/skills/security/SKILL.md +33 -0
- package/skills/skill-creator/.plugin/plugin.json +17 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/README.md +182 -0
- package/skills/skill-creator/SKILL.md +545 -0
- package/skills/skill-creator/references/output-patterns.md +82 -0
- package/skills/skill-creator/references/workflows.md +28 -0
- package/skills/skill-creator/scripts/init_skill.py +303 -0
- package/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/skills/slack-channel-monitor/.plugin/plugin.json +21 -0
- package/skills/slack-channel-monitor/README.md +91 -0
- package/skills/slack-channel-monitor/SKILL.md +276 -0
- package/skills/slack-channel-monitor/commands/slack-monitor:poll.md +8 -0
- package/skills/slack-channel-monitor/references/slack-api.md +207 -0
- package/skills/slack-channel-monitor/references/state-schema.md +180 -0
- package/skills/slack-channel-monitor/scripts/main.py +962 -0
- package/skills/slack-standup-digest/.plugin/plugin.json +21 -0
- package/skills/slack-standup-digest/README.md +34 -0
- package/skills/slack-standup-digest/SKILL.md +92 -0
- package/skills/slack-standup-digest/commands/standup-digest:setup.md +8 -0
- package/skills/spark-version-upgrade/.plugin/plugin.json +20 -0
- package/skills/spark-version-upgrade/README.md +54 -0
- package/skills/spark-version-upgrade/SKILL.md +233 -0
- package/skills/ssh/.plugin/plugin.json +18 -0
- package/skills/ssh/README.md +140 -0
- package/skills/ssh/SKILL.md +135 -0
- package/skills/swift-linux/.plugin/plugin.json +17 -0
- package/skills/swift-linux/README.md +86 -0
- package/skills/swift-linux/SKILL.md +81 -0
- package/skills/theme-factory/.plugin/plugin.json +19 -0
- package/skills/theme-factory/LICENSE.txt +202 -0
- package/skills/theme-factory/README.md +58 -0
- package/skills/theme-factory/SKILL.md +59 -0
- package/skills/theme-factory/theme-showcase.pdf +0 -0
- package/skills/theme-factory/themes/arctic-frost.md +19 -0
- package/skills/theme-factory/themes/botanical-garden.md +19 -0
- package/skills/theme-factory/themes/desert-rose.md +19 -0
- package/skills/theme-factory/themes/forest-canopy.md +19 -0
- package/skills/theme-factory/themes/golden-hour.md +19 -0
- package/skills/theme-factory/themes/midnight-galaxy.md +19 -0
- package/skills/theme-factory/themes/modern-minimalist.md +19 -0
- package/skills/theme-factory/themes/ocean-depths.md +19 -0
- package/skills/theme-factory/themes/sunset-boulevard.md +19 -0
- package/skills/theme-factory/themes/tech-innovation.md +19 -0
- package/skills/uv/.plugin/plugin.json +18 -0
- package/skills/uv/README.md +5 -0
- package/skills/uv/SKILL.md +95 -0
- package/skills/uv/references/README.md +5 -0
- package/skills/vercel/.plugin/plugin.json +18 -0
- package/skills/vercel/README.md +108 -0
- package/skills/vercel/SKILL.md +103 -0
- package/tests/test_add_skill_installs_to_agents_dir.py +42 -0
- package/tests/test_catalogs.py +109 -0
- package/tests/test_code_review_risk_evaluation.py +94 -0
- package/tests/test_issue_duplicate_checker.py +240 -0
- package/tests/test_openhands_api_python.py +152 -0
- package/tests/test_plugin_manifest.py +83 -0
- package/tests/test_pr_review_diff_payload.py +202 -0
- package/tests/test_pr_review_feedback.py +263 -0
- package/tests/test_pr_review_prompt.py +152 -0
- package/tests/test_pr_review_review_context.py +253 -0
- package/tests/test_qa_changes.py +232 -0
- package/tests/test_qa_changes_evaluation.py +259 -0
- package/tests/test_release_notes_generator.py +990 -0
- package/tests/test_sdk_loading.py +150 -0
- package/tests/test_skill_plugin_loading.py +149 -0
- package/tests/test_skills_have_readme.py +66 -0
- package/tests/test_sync_extensions.py +292 -0
- package/tests/test_workflow_sync.py +46 -0
- package/utils/analysis/README.md +7 -0
- package/utils/analysis/laminar_signals/README.md +211 -0
- package/utils/analysis/laminar_signals/analyze.py +780 -0
- package/utils/analysis/laminar_signals/templates/default.j2 +49 -0
- package/utils/analysis/laminar_signals/templates/pr_review.j2 +61 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-repo-monitor
|
|
3
|
+
description: >
|
|
4
|
+
This skill should be used when the user asks to "monitor a GitHub repository",
|
|
5
|
+
"watch GitHub for issues or PRs", "respond to @OpenHands mentions on GitHub",
|
|
6
|
+
"set up an OpenHands GitHub integration", "trigger OpenHands from a GitHub
|
|
7
|
+
comment", or "poll a GitHub repo for a trigger phrase". Guides the user
|
|
8
|
+
through creating a cron automation that polls a single repository and starts
|
|
9
|
+
an OpenHands conversation whenever a configurable trigger phrase is detected
|
|
10
|
+
in an issue or PR comment.
|
|
11
|
+
triggers:
|
|
12
|
+
- /github-monitor:poll
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# GitHub Repository Monitor
|
|
16
|
+
|
|
17
|
+
Create a cron automation that polls a single GitHub repository on a
|
|
18
|
+
configurable schedule (default: every minute).
|
|
19
|
+
|
|
20
|
+
When a comment on an issue or PR contains the **trigger phrase**
|
|
21
|
+
(default: `@OpenHands`) it:
|
|
22
|
+
|
|
23
|
+
1. Posts a GitHub comment acknowledging the request with a conversation link.
|
|
24
|
+
2. Creates an OpenHands conversation pre-loaded with the issue/PR title, body,
|
|
25
|
+
labels, and recent comment history for full context.
|
|
26
|
+
3. Posts a summary GitHub comment when the conversation finishes.
|
|
27
|
+
|
|
28
|
+
On every subsequent run:
|
|
29
|
+
- New trigger comments on an already-tracked issue/PR are forwarded to the
|
|
30
|
+
running conversation (or re-open a previously closed one).
|
|
31
|
+
- When a conversation goes idle/finished/error the agent's final response
|
|
32
|
+
is posted back as a GitHub comment.
|
|
33
|
+
|
|
34
|
+
> **Local mode only.** This automation targets the local OpenHands setup
|
|
35
|
+
> (`dev:automation` stack). A cloud/webhook variant is out of scope here.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Prerequisites
|
|
40
|
+
|
|
41
|
+
### Required secret
|
|
42
|
+
|
|
43
|
+
Verify that the following secret is set in **OpenHands Settings → Secrets**
|
|
44
|
+
before proceeding:
|
|
45
|
+
|
|
46
|
+
| Secret name | Token type | Minimum permissions |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `GITHUB_TOKEN` | Classic PAT | `repo` (private repos) or `public_repo` (public repos) |
|
|
49
|
+
| `GITHUB_TOKEN` | Fine-grained PAT | Issues: Read and Write |
|
|
50
|
+
|
|
51
|
+
Check with:
|
|
52
|
+
```bash
|
|
53
|
+
curl -s https://api.github.com/user \
|
|
54
|
+
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
55
|
+
-H "Accept: application/vnd.github+json" \
|
|
56
|
+
| python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('login') or d.get('message'))"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
If the token is missing, inform the user and stop — the automation cannot
|
|
60
|
+
function without GitHub credentials.
|
|
61
|
+
|
|
62
|
+
### Optional secret
|
|
63
|
+
|
|
64
|
+
| Secret name | Default | Purpose |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `OPENHANDS_URL` | `http://localhost:8000` | Base URL used to build conversation links in GitHub comments |
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Setup Workflow
|
|
71
|
+
|
|
72
|
+
Follow these steps in order.
|
|
73
|
+
|
|
74
|
+
### Step 1 - Verify GITHUB_TOKEN
|
|
75
|
+
|
|
76
|
+
Fetch the secret and run the `curl` check above.
|
|
77
|
+
|
|
78
|
+
- If the secret is absent: tell the user
|
|
79
|
+
*"GITHUB_TOKEN is not set. Please add it in OpenHands Settings → Secrets
|
|
80
|
+
(classic PAT with `repo` or `public_repo` scope, or a fine-grained PAT
|
|
81
|
+
with Issues: Read and Write)."* Then stop.
|
|
82
|
+
|
|
83
|
+
- If the API returns a non-200 or `{"message": "Bad credentials"}`:
|
|
84
|
+
tell the user the token is invalid and ask them to update it.
|
|
85
|
+
|
|
86
|
+
### Step 2 - Collect repository
|
|
87
|
+
|
|
88
|
+
Ask the user: *"Which GitHub repository should be monitored?
|
|
89
|
+
(Format: `owner/repo`, e.g. `microsoft/vscode`)"*
|
|
90
|
+
|
|
91
|
+
Validate access and write permissions:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
curl -s "https://api.github.com/repos/{owner}/{repo}" \
|
|
95
|
+
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
96
|
+
-H "Accept: application/vnd.github+json" \
|
|
97
|
+
| python3 -c "
|
|
98
|
+
import json, sys
|
|
99
|
+
d = json.load(sys.stdin)
|
|
100
|
+
if 'message' in d:
|
|
101
|
+
print('ERROR:', d['message'])
|
|
102
|
+
else:
|
|
103
|
+
perms = d.get('permissions', {})
|
|
104
|
+
print(f\"Accessible. Private: {d.get('private')}. Permissions: {perms}\")
|
|
105
|
+
"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- If `message: Not Found` or `message: Bad credentials` →
|
|
109
|
+
inform the user and ask them to check the repo name and token.
|
|
110
|
+
- If the repo is private and `permissions.push` is `false` →
|
|
111
|
+
inform the user the token does not have write access and comments will fail.
|
|
112
|
+
- If the check passes, record `REPO = "{owner}/{repo}"`.
|
|
113
|
+
|
|
114
|
+
### Step 3 - Collect trigger phrase
|
|
115
|
+
|
|
116
|
+
Ask the user: *"What trigger phrase should OpenHands respond to?
|
|
117
|
+
(Press Enter to use the default: `@OpenHands`)"*
|
|
118
|
+
|
|
119
|
+
Accepted values: any non-empty string unlikely to appear by accident.
|
|
120
|
+
|
|
121
|
+
Record as `TRIGGER_PHRASE`. Default: `"@openhands"`.
|
|
122
|
+
|
|
123
|
+
### Step 4 - Collect allowed GitHub logins
|
|
124
|
+
|
|
125
|
+
Ask the user: *"Which GitHub users may trigger this automation?
|
|
126
|
+
Press Enter to allow only the authenticated `GITHUB_TOKEN` owner.
|
|
127
|
+
You may also provide comma-separated GitHub logins, or `*` to allow any
|
|
128
|
+
non-bot commenter on the monitored repository."*
|
|
129
|
+
|
|
130
|
+
Map the answer to `ALLOWED_GITHUB_LOGINS`:
|
|
131
|
+
|
|
132
|
+
| User answer | `ALLOWED_GITHUB_LOGINS` value |
|
|
133
|
+
|---|---|
|
|
134
|
+
| Empty/default | `["<TOKEN_OWNER>"]` |
|
|
135
|
+
| `enyst,tofarr` | `["enyst", "tofarr"]` |
|
|
136
|
+
| `*` | `["*"]` |
|
|
137
|
+
|
|
138
|
+
Default to token-owner-only unless the user explicitly chooses a broader
|
|
139
|
+
allowlist. Record as `ALLOWED_GITHUB_LOGINS`.
|
|
140
|
+
|
|
141
|
+
### Step 5 - Collect event types
|
|
142
|
+
|
|
143
|
+
Ask the user: *"Which event types should be monitored?
|
|
144
|
+
Choose one or more:*
|
|
145
|
+
*1. Issue and PR comments (default)*
|
|
146
|
+
*2. PR inline review comments*
|
|
147
|
+
*3. Both*
|
|
148
|
+
*(Press Enter to accept the default: issue and PR comments.)"*
|
|
149
|
+
|
|
150
|
+
Map the choice to the `EVENT_TYPES` list:
|
|
151
|
+
|
|
152
|
+
| Choice | `EVENT_TYPES` value |
|
|
153
|
+
|---|---|
|
|
154
|
+
| 1 (default) | `["issue_comment"]` |
|
|
155
|
+
| 2 | `["pr_review_comment"]` |
|
|
156
|
+
| 3 | `["issue_comment", "pr_review_comment"]` |
|
|
157
|
+
|
|
158
|
+
### Step 6 - Collect cron schedule
|
|
159
|
+
|
|
160
|
+
Ask the user: *"How often should the automation poll GitHub?
|
|
161
|
+
(Press Enter for the default: every minute.
|
|
162
|
+
Use a cron expression for a different interval, e.g.:
|
|
163
|
+
`*/5 * * * *` = every 5 minutes,
|
|
164
|
+
`0 * * * *` = every hour)"*
|
|
165
|
+
|
|
166
|
+
Default: `* * * * *` (every minute).
|
|
167
|
+
|
|
168
|
+
Record as `CRON_SCHEDULE`.
|
|
169
|
+
|
|
170
|
+
### Step 7 - Generate the automation script
|
|
171
|
+
|
|
172
|
+
Read `scripts/main.py` from this skill's directory. Apply exactly five
|
|
173
|
+
constant substitutions near the top of the file:
|
|
174
|
+
|
|
175
|
+
| Placeholder | Replace with |
|
|
176
|
+
|---|---|
|
|
177
|
+
| `REPO = "owner/repo"` | `REPO = "{owner_repo}"` |
|
|
178
|
+
| `TRIGGER_PHRASE = "@openhands"` | `TRIGGER_PHRASE = "{trigger_phrase_lower}"` |
|
|
179
|
+
| `EVENT_TYPES = ["issue_comment"]` | `EVENT_TYPES = {event_types_list}` |
|
|
180
|
+
| `ALLOWED_GITHUB_LOGINS = ["<TOKEN_OWNER>"]` | `ALLOWED_GITHUB_LOGINS = {allowed_logins_list}` |
|
|
181
|
+
| `DEFAULT_OPENHANDS_URL = "http://localhost:8000"` | `DEFAULT_OPENHANDS_URL = "{url}"` (keep default if the user has no preference) |
|
|
182
|
+
|
|
183
|
+
Write the customised script to a temporary build directory:
|
|
184
|
+
```bash
|
|
185
|
+
mkdir -p /tmp/github-monitor-build
|
|
186
|
+
# (write the customised main.py to /tmp/github-monitor-build/main.py)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Validate syntax before packaging:
|
|
190
|
+
```bash
|
|
191
|
+
python3 -m py_compile /tmp/github-monitor-build/main.py && echo "Syntax OK"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Fix any syntax errors before proceeding.
|
|
195
|
+
|
|
196
|
+
### Step 8 - Package and upload
|
|
197
|
+
|
|
198
|
+
Determine the Automation backend URL and auth from the `<RUNTIME_SERVICES>`
|
|
199
|
+
block in your system context:
|
|
200
|
+
- Use the **Automation backend** `url_from_agent` as `OPENHANDS_HOST`
|
|
201
|
+
- Auth: `X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY`
|
|
202
|
+
|
|
203
|
+
If no Automation backend is listed in `<RUNTIME_SERVICES>`, stop and tell
|
|
204
|
+
the user to start the full automation stack.
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
tar -czf /tmp/github-monitor.tar.gz -C /tmp/github-monitor-build .
|
|
208
|
+
|
|
209
|
+
# OPENHANDS_HOST: read from <RUNTIME_SERVICES> Automation backend url_from_agent
|
|
210
|
+
OPENHANDS_HOST="<automation-url-from-runtime-services>"
|
|
211
|
+
|
|
212
|
+
TARBALL_PATH=$(curl -s -X POST \
|
|
213
|
+
"${OPENHANDS_HOST}/api/automation/v1/uploads?name=github-repo-monitor" \
|
|
214
|
+
-H "X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY" \
|
|
215
|
+
-H "Content-Type: application/gzip" \
|
|
216
|
+
--data-binary @/tmp/github-monitor.tar.gz \
|
|
217
|
+
| python3 -c "import json,sys; print(json.load(sys.stdin)['tarball_path'])")
|
|
218
|
+
|
|
219
|
+
echo "Uploaded: $TARBALL_PATH"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Step 9 - Create the automation
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
curl -s -X POST "${OPENHANDS_HOST}/api/automation/v1" \
|
|
226
|
+
-H "X-Session-API-Key: $OPENHANDS_AUTOMATION_API_KEY" \
|
|
227
|
+
-H "Content-Type: application/json" \
|
|
228
|
+
-d "{
|
|
229
|
+
\"name\": \"GitHub Monitor: {owner}/{repo}\",
|
|
230
|
+
\"trigger\": {\"type\": \"cron\", \"schedule\": \"{cron_schedule}\"},
|
|
231
|
+
\"tarball_path\": \"$TARBALL_PATH\",
|
|
232
|
+
\"entrypoint\": \"python3 main.py\",
|
|
233
|
+
\"timeout\": 55
|
|
234
|
+
}" | python3 -m json.tool
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Record the returned `id`.
|
|
238
|
+
|
|
239
|
+
### Step 10 - Confirm
|
|
240
|
+
|
|
241
|
+
Tell the user:
|
|
242
|
+
|
|
243
|
+
> ✅ **GitHub Repository Monitor** is running!
|
|
244
|
+
>
|
|
245
|
+
> - Automation ID: `{id}`
|
|
246
|
+
> - Repository: `{owner}/{repo}`
|
|
247
|
+
> - Trigger phrase: `{phrase}`
|
|
248
|
+
> - Event types: `{event_types}`
|
|
249
|
+
> - Allowed GitHub logins: `{allowed_logins}`
|
|
250
|
+
> - Polling schedule: `{cron_schedule}`
|
|
251
|
+
> - State file: `~/.openhands/workspaces/automation-state/github_poller_{id}.json`
|
|
252
|
+
>
|
|
253
|
+
> From an allowed GitHub login, post a comment containing `{phrase}` on any
|
|
254
|
+
> issue or PR in `{owner}/{repo}` to test it. OpenHands will acknowledge with
|
|
255
|
+
> a comment and a link to the new conversation.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Runtime Behaviour (per poll)
|
|
260
|
+
|
|
261
|
+
Each cron run executes `main.py`, which:
|
|
262
|
+
|
|
263
|
+
1. **Loads state** from the JSON file (see `references/state-schema.md`).
|
|
264
|
+
2. **Resolves and validates GITHUB_TOKEN** — aborts immediately if absent or invalid.
|
|
265
|
+
3. **Polls for new events** since the previous `last_poll` timestamp:
|
|
266
|
+
- `GET /repos/{owner}/{repo}/issues/comments?since=…` for `issue_comment`
|
|
267
|
+
- `GET /repos/{owner}/{repo}/pulls/comments?since=…` for `pr_review_comment`
|
|
268
|
+
4. **Processes matching comments** in chronological order:
|
|
269
|
+
- Skips bot accounts (login ending in `[bot]`) to avoid feedback loops.
|
|
270
|
+
- Skips already-processed comment IDs.
|
|
271
|
+
- Skips comments from logins outside `ALLOWED_GITHUB_LOGINS`.
|
|
272
|
+
- Checks body for the trigger phrase (case-insensitive).
|
|
273
|
+
- Extracts the issue/PR number from the comment URL.
|
|
274
|
+
5. **For each trigger comment**, per issue/PR:
|
|
275
|
+
- **Active conversation** → forwards the new comment directly.
|
|
276
|
+
- **Closed conversation** → tries to re-open it; falls back to creating
|
|
277
|
+
a new conversation if the old one is unreachable.
|
|
278
|
+
- **No conversation** → fetches full context (title, body, labels, last
|
|
279
|
+
10 comments) and creates a new conversation with a detailed prompt.
|
|
280
|
+
- Posts a GitHub comment: *"🤖 OpenHands is on it! View progress: {url}"*
|
|
281
|
+
6. **Checks active conversations** for completion:
|
|
282
|
+
- If `status ∈ {idle, finished, error, stuck}` and enough time has passed
|
|
283
|
+
since creation (debounce), fetches the agent's final response and posts
|
|
284
|
+
it as a GitHub comment. Marks the conversation `closed`.
|
|
285
|
+
7. **Saves state** and fires the completion callback.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Additional Resources
|
|
290
|
+
|
|
291
|
+
### Reference Files
|
|
292
|
+
|
|
293
|
+
- **`references/state-schema.md`** - State JSON schema, field definitions,
|
|
294
|
+
and conversation lifecycle diagram.
|
|
295
|
+
- **`references/github-api.md`** - GitHub API endpoint reference, token
|
|
296
|
+
scopes, rate limits, and common error codes.
|
|
297
|
+
|
|
298
|
+
### Script Template
|
|
299
|
+
|
|
300
|
+
- **`scripts/main.py`** - The complete automation script. Customise the four
|
|
301
|
+
constants at the top (`REPO`, `TRIGGER_PHRASE`, `EVENT_TYPES`,
|
|
302
|
+
`DEFAULT_OPENHANDS_URL`) before packaging.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Troubleshooting
|
|
307
|
+
|
|
308
|
+
| Symptom | Likely cause | Fix |
|
|
309
|
+
|---|---|---|
|
|
310
|
+
| Bot doesn't respond to comments | `GITHUB_TOKEN` missing or wrong scopes | Verify token with `curl /user`; check scopes in Step 1 |
|
|
311
|
+
| "Bad credentials" in run logs | Token expired | Rotate token and update the secret in Settings |
|
|
312
|
+
| 404 on repo access | Repo name wrong or token has no access | Re-check `owner/repo` spelling; add token as collaborator |
|
|
313
|
+
| Comments posted but no conversation created | Agent server URL wrong | Check `OPENHANDS_URL` secret and `AGENT_SERVER_URL` env var |
|
|
314
|
+
| Same comment processed twice | `processed_comment_ids` cleared | State file was deleted; harmless but duplicate comment may appear |
|
|
315
|
+
| Summary never posted | Conversation stuck in `running` | Open the conversation in the OpenHands UI; agent may need input |
|
|
316
|
+
| No events detected after first run | `last_poll` in the future | Delete the state file to reset; it will be recreated on next run |
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
# auto-generated by sync_extensions.py
|
|
3
|
+
description: This skill should be used when the user asks to "monitor a GitHub repository", "watch GitHub for issues or PRs", "respond to @OpenHands mentions on GitHub", "set up an OpenHands GitHub integration", "trigger OpenHands from a GitHub comment", or "poll a GitHub repo for a trigger phrase". Guides the user through creating a cron automation that polls a single repository and starts an OpenHands conversation whenever a configurable trigger phrase is detected in an issue or PR comment.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Read and follow the complete instructions in the SKILL.md file located in this skill's directory.
|
|
7
|
+
|
|
8
|
+
$ARGUMENTS
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# GitHub API Reference
|
|
2
|
+
|
|
3
|
+
Quick reference for the endpoints, authentication, and rate limits used by
|
|
4
|
+
the GitHub Repository Monitor automation.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Authentication
|
|
9
|
+
|
|
10
|
+
All requests use Bearer authentication:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Authorization: Bearer {GITHUB_TOKEN}
|
|
14
|
+
Accept: application/vnd.github+json
|
|
15
|
+
X-GitHub-Api-Version: 2022-11-28
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Token Types and Required Scopes
|
|
21
|
+
|
|
22
|
+
### Classic Personal Access Token
|
|
23
|
+
|
|
24
|
+
| Scope | Grants |
|
|
25
|
+
|-------|--------|
|
|
26
|
+
| `repo` | Full access to private and public repos (read + write issues/PRs) |
|
|
27
|
+
| `public_repo` | Write access to public repos only (sufficient for public repos) |
|
|
28
|
+
|
|
29
|
+
### Fine-Grained Personal Access Token
|
|
30
|
+
|
|
31
|
+
| Permission | Level |
|
|
32
|
+
|------------|-------|
|
|
33
|
+
| Issues | Read and Write |
|
|
34
|
+
| Pull requests | Read (optional, for fetching PR metadata) |
|
|
35
|
+
|
|
36
|
+
### Checking Token Scopes
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
curl -I https://api.github.com/user \
|
|
40
|
+
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
41
|
+
| grep -i x-oauth-scopes
|
|
42
|
+
# X-OAuth-Scopes: repo, public_repo
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Fine-grained PATs do not return `X-OAuth-Scopes`; the script relies on the
|
|
46
|
+
`permissions` field in the repo response instead.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Endpoints Used
|
|
51
|
+
|
|
52
|
+
### Verify token identity
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
GET /user
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Returns the authenticated user. Use to verify the token is valid.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### Verify repo access and permissions
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
GET /repos/{owner}/{repo}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Key fields in the response:
|
|
69
|
+
|
|
70
|
+
| Field | Type | Description |
|
|
71
|
+
|-------|------|-------------|
|
|
72
|
+
| `private` | bool | Whether the repo is private |
|
|
73
|
+
| `permissions.push` | bool | Token has write access (required for private repos) |
|
|
74
|
+
| `permissions.pull` | bool | Token has read access |
|
|
75
|
+
| `full_name` | string | `owner/repo` |
|
|
76
|
+
|
|
77
|
+
Error codes:
|
|
78
|
+
- `404` — Repo not found or token has no read access.
|
|
79
|
+
- `403` — Token exists but is blocked from this resource.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
### Poll issue and PR comments
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
GET /repos/{owner}/{repo}/issues/comments
|
|
87
|
+
?since={ISO 8601 UTC}
|
|
88
|
+
&sort=created
|
|
89
|
+
&direction=asc
|
|
90
|
+
&per_page=100
|
|
91
|
+
&page={n}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Returns all comments on issues **and** PRs (PRs are a superset of issues in
|
|
95
|
+
GitHub's API). The `since` parameter filters to comments created **at or
|
|
96
|
+
after** the given timestamp.
|
|
97
|
+
|
|
98
|
+
Key fields per comment:
|
|
99
|
+
|
|
100
|
+
| Field | Description |
|
|
101
|
+
|-------|-------------|
|
|
102
|
+
| `id` | Integer comment ID (used for deduplication) |
|
|
103
|
+
| `body` | Comment text |
|
|
104
|
+
| `user.login` | Author username |
|
|
105
|
+
| `user.type` | `"User"` or `"Bot"` |
|
|
106
|
+
| `created_at` | ISO 8601 UTC creation timestamp |
|
|
107
|
+
| `html_url` | Direct link to the comment |
|
|
108
|
+
| `issue_url` | API URL of the parent issue/PR (extract number from last path segment) |
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### Poll PR inline review comments
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
GET /repos/{owner}/{repo}/pulls/comments
|
|
116
|
+
?since={ISO 8601 UTC}
|
|
117
|
+
&sort=created
|
|
118
|
+
&direction=asc
|
|
119
|
+
&per_page=100
|
|
120
|
+
&page={n}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Returns inline review comments on PR diffs.
|
|
124
|
+
|
|
125
|
+
Key fields per comment:
|
|
126
|
+
|
|
127
|
+
| Field | Description |
|
|
128
|
+
|-------|-------------|
|
|
129
|
+
| `id` | Integer comment ID |
|
|
130
|
+
| `body` | Comment text |
|
|
131
|
+
| `user.login` | Author username |
|
|
132
|
+
| `pull_request_url` | API URL of the parent PR (extract number from last path segment) |
|
|
133
|
+
| `path` | File path the comment was left on |
|
|
134
|
+
| `line` | Line number in the file (nullable) |
|
|
135
|
+
| `created_at` | ISO 8601 UTC creation timestamp |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Fetch issue/PR metadata
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
GET /repos/{owner}/{repo}/issues/{issue_number}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Works for both issues and pull requests. To distinguish:
|
|
146
|
+
- Response contains `pull_request` key → it's a PR.
|
|
147
|
+
- No `pull_request` key → it's a regular issue.
|
|
148
|
+
|
|
149
|
+
Key fields:
|
|
150
|
+
|
|
151
|
+
| Field | Description |
|
|
152
|
+
|-------|-------------|
|
|
153
|
+
| `number` | Issue/PR number |
|
|
154
|
+
| `title` | Title string |
|
|
155
|
+
| `body` | Description text (can be null) |
|
|
156
|
+
| `state` | `"open"` or `"closed"` |
|
|
157
|
+
| `html_url` | Browser URL |
|
|
158
|
+
| `labels[].name` | Label names |
|
|
159
|
+
| `pull_request.url` | Present only if this is a PR |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### Fetch recent comments for context
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
GET /repos/{owner}/{repo}/issues/{issue_number}/comments
|
|
167
|
+
?per_page=100
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Returns all issue/PR comments in chronological order. The script fetches
|
|
171
|
+
all pages and takes the last `CONTEXT_COMMENT_LIMIT` (default 10) entries.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### Post a comment
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
POST /repos/{owner}/{repo}/issues/{issue_number}/comments
|
|
179
|
+
|
|
180
|
+
Body: { "body": "comment text (Markdown supported)" }
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Works for both issues and PRs. Returns the created comment object including
|
|
184
|
+
its `id` and `html_url`.
|
|
185
|
+
|
|
186
|
+
Error codes:
|
|
187
|
+
- `403` — Token lacks write permission.
|
|
188
|
+
- `404` — Repo or issue not found.
|
|
189
|
+
- `410` — Issue is locked; comments are disabled.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Rate Limits
|
|
194
|
+
|
|
195
|
+
| Tier | Limit | Notes |
|
|
196
|
+
|------|-------|-------|
|
|
197
|
+
| Authenticated requests | 5,000 / hour | Per token |
|
|
198
|
+
| Search API | 30 / minute | Not used by this script |
|
|
199
|
+
| Secondary rate limit | Varies | Triggered by rapid POST bursts; unlikely at 1-min polling |
|
|
200
|
+
|
|
201
|
+
At one poll per minute on a moderately active repo:
|
|
202
|
+
- ~2 GET calls per run baseline (user + repo)
|
|
203
|
+
- ~1–3 additional GETs per trigger event (issue context + comment history)
|
|
204
|
+
- ~1–2 POSTs per trigger event (acknowledgement comment + optional summary)
|
|
205
|
+
|
|
206
|
+
Typical usage: **< 20 requests/hour** for a quiet repo,
|
|
207
|
+
**< 300 requests/hour** for a very active repo (still well within the 5,000 limit).
|
|
208
|
+
|
|
209
|
+
Check remaining quota with:
|
|
210
|
+
```bash
|
|
211
|
+
curl -s https://api.github.com/rate_limit \
|
|
212
|
+
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
213
|
+
| python3 -c "
|
|
214
|
+
import json, sys
|
|
215
|
+
d = json.load(sys.stdin)
|
|
216
|
+
core = d['resources']['core']
|
|
217
|
+
print(f\"Remaining: {core['remaining']}/{core['limit']} Reset: {core['reset']}\")
|
|
218
|
+
"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Common Error Codes
|
|
224
|
+
|
|
225
|
+
| Code | Meaning | Typical fix |
|
|
226
|
+
|------|---------|-------------|
|
|
227
|
+
| 401 | Bad credentials / token expired | Rotate token; update the secret |
|
|
228
|
+
| 403 | Forbidden (scope missing or repo blocked) | Add required scope; check org SSO |
|
|
229
|
+
| 404 | Resource not found or no read access | Check repo name; ensure token has access |
|
|
230
|
+
| 410 | Gone (issue locked or deleted) | Harmless — skip this issue |
|
|
231
|
+
| 422 | Unprocessable entity (e.g., body too long) | Truncate comment body |
|
|
232
|
+
| 429 | Rate limit hit (secondary) | Slow down; add sleep between requests |
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Bot Detection
|
|
237
|
+
|
|
238
|
+
GitHub sets `user.type = "Bot"` for GitHub Apps and some bots. Classic bot
|
|
239
|
+
accounts (created as regular users) may instead have logins ending in
|
|
240
|
+
`[bot]` (e.g. `dependabot[bot]`). The script skips both patterns to avoid
|
|
241
|
+
feedback loops with other automation.
|