@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,90 @@
|
|
|
1
|
+
"""Prompt template for the release notes agent."""
|
|
2
|
+
|
|
3
|
+
PROMPT = """Write official release notes for `{repo_name}` tag `{tag}`.
|
|
4
|
+
|
|
5
|
+
Use the structured release data below as your primary source of truth. You may inspect the checked-out repository if it helps you judge significance or match release-note style, but do not ask follow-up questions.
|
|
6
|
+
|
|
7
|
+
Your job is editorial, not mechanical:
|
|
8
|
+
- decide which PRs are important enough to mention
|
|
9
|
+
- group related PRs into a single bullet when they form one coherent feature or fix
|
|
10
|
+
- for larger releases, aggressively compress the notes into a shorter set of higher-signal bullets instead of listing one bullet per PR
|
|
11
|
+
- if a section would have more than 5 bullets, merge same-theme items until the section is scannable
|
|
12
|
+
- omit trivial, repetitive, or low-signal changes from the final notes
|
|
13
|
+
- prefer end-user impact over implementation detail
|
|
14
|
+
- prioritize public APIs, user-visible capabilities, security fixes, supported integrations/models, and operational changes users directly invoke
|
|
15
|
+
- treat toolkit-maintainer or contributor-facing changes as secondary unless they materially change how end users or client developers adopt, run, or integrate the project
|
|
16
|
+
- changes that mostly affect CI, internal prompts, benchmarks, workflow inputs, refactors, contributor ergonomics, or toolkit implementation details should stay in the small/internal appendix unless they are unusually significant
|
|
17
|
+
- use `### 📚 Documentation` only for notable docs/reference/policy updates that matter to users or client developers; public API additions still belong in `### ✨ New Features`
|
|
18
|
+
- omit prompt wording, benchmark plumbing, workflow maintenance, and similar maintainer-only changes unless they materially alter observable user behavior
|
|
19
|
+
- start with a short, conversational 1-2 sentence overview of the release before the categorized sections
|
|
20
|
+
- if you add top-level highlight bullets, keep them to at most 3 and reserve them for the biggest user-facing changes
|
|
21
|
+
- treat the suggested category as a hint, not a rule
|
|
22
|
+
- when `include_internal` is false, omit internal-only work unless it is important for users
|
|
23
|
+
- use imperative mood
|
|
24
|
+
- keep each bullet to one line
|
|
25
|
+
- every change bullet must end with explicit references for each included item
|
|
26
|
+
- format PR references as `(#123) @username`; if you group multiple PRs, include each reference explicitly, for example `(#123) @alice, (#124) @bob`
|
|
27
|
+
- if you mention a standalone commit instead of a PR, format it as `(abc1234) @username`
|
|
28
|
+
- include every new contributor listed below in the `### 👥 New Contributors` section
|
|
29
|
+
- for breaking changes, briefly note the migration path when the provided context makes it clear
|
|
30
|
+
|
|
31
|
+
Return markdown only. Do not wrap the result in a code fence.
|
|
32
|
+
|
|
33
|
+
Required structure:
|
|
34
|
+
- `## [{tag}] - {date}`
|
|
35
|
+
- a short conversational overview paragraph immediately after the title
|
|
36
|
+
- optional top-level highlight bullets (maximum 3) before the categorized sections
|
|
37
|
+
- `### ⚠️ Breaking Changes` when applicable
|
|
38
|
+
- `### ✨ New Features` when applicable
|
|
39
|
+
- `### 🐛 Bug Fixes` when applicable
|
|
40
|
+
- `### 📚 Documentation` only when notable
|
|
41
|
+
- `### 🏗️ Internal/Infrastructure` only when `include_internal` is true and the changes are worth mentioning
|
|
42
|
+
- `### 👥 New Contributors` when there are any
|
|
43
|
+
- `**Full Changelog**: {full_changelog_url}` at the end
|
|
44
|
+
|
|
45
|
+
Release metadata:
|
|
46
|
+
- Repository: {repo_name}
|
|
47
|
+
- Current tag: {tag}
|
|
48
|
+
- Previous tag: {previous_tag}
|
|
49
|
+
- Release date: {date}
|
|
50
|
+
- Commits in range: {commit_count}
|
|
51
|
+
- Include internal section: {include_internal}
|
|
52
|
+
- Output format: {output_format}
|
|
53
|
+
|
|
54
|
+
Candidate changes:
|
|
55
|
+
{change_candidates}
|
|
56
|
+
|
|
57
|
+
New contributors:
|
|
58
|
+
{new_contributors}
|
|
59
|
+
|
|
60
|
+
Full changelog URL:
|
|
61
|
+
{full_changelog_url}
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def format_prompt(
|
|
66
|
+
*,
|
|
67
|
+
repo_name: str,
|
|
68
|
+
tag: str,
|
|
69
|
+
previous_tag: str,
|
|
70
|
+
date: str,
|
|
71
|
+
commit_count: int,
|
|
72
|
+
include_internal: bool,
|
|
73
|
+
output_format: str,
|
|
74
|
+
full_changelog_url: str,
|
|
75
|
+
change_candidates: str,
|
|
76
|
+
new_contributors: str,
|
|
77
|
+
) -> str:
|
|
78
|
+
"""Format the release-notes prompt."""
|
|
79
|
+
return PROMPT.format(
|
|
80
|
+
repo_name=repo_name,
|
|
81
|
+
tag=tag,
|
|
82
|
+
previous_tag=previous_tag,
|
|
83
|
+
date=date,
|
|
84
|
+
commit_count=commit_count,
|
|
85
|
+
include_internal=str(include_internal).lower(),
|
|
86
|
+
output_format=output_format,
|
|
87
|
+
full_changelog_url=full_changelog_url,
|
|
88
|
+
change_candidates=change_candidates,
|
|
89
|
+
new_contributors=new_contributors,
|
|
90
|
+
)
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate attribution coverage in generated release notes."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import re
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from generate_release_notes import CATEGORIES, ReleaseNotes, generate_release_notes, get_env
|
|
11
|
+
|
|
12
|
+
PR_REF_PATTERN = re.compile(r"#(\d+)\b")
|
|
13
|
+
COMMIT_REF_PATTERN = re.compile(r"\(([0-9a-f]{7,40})\)")
|
|
14
|
+
USER_HANDLE_PATTERN = re.compile(r"@([A-Za-z0-9][A-Za-z0-9_\-\[\]]*)")
|
|
15
|
+
NEW_CONTRIBUTORS_HEADING = "### 👥 New Contributors"
|
|
16
|
+
COVERAGE_HEADING = "### 🔎 Small Fixes/Internal Changes"
|
|
17
|
+
REFERENCE_CATEGORY_ORDER = ["breaking", "features", "fixes", "docs", "internal", "other"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class CoverageSummary:
|
|
22
|
+
"""Summary of attribution coverage found in release notes."""
|
|
23
|
+
|
|
24
|
+
bullet_count: int
|
|
25
|
+
referenced_prs: list[int]
|
|
26
|
+
referenced_authors: list[str]
|
|
27
|
+
referenced_commits: list[str]
|
|
28
|
+
required_reference_count: int
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class ValidationContext:
|
|
33
|
+
"""Parsed validation context for a single release note run."""
|
|
34
|
+
|
|
35
|
+
reference_authors: dict[str, str]
|
|
36
|
+
reference_order: list[str]
|
|
37
|
+
change_section_headings: set[str]
|
|
38
|
+
expected_new_contributors: dict[str, int | None]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ReleaseNotesValidationError(ValueError):
|
|
42
|
+
"""Raised when generated release notes violate attribution rules."""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class MentionScanResult:
|
|
47
|
+
"""Collected ref/author coverage from markdown."""
|
|
48
|
+
|
|
49
|
+
covered_refs: set[str]
|
|
50
|
+
referenced_prs: set[int]
|
|
51
|
+
referenced_authors: set[str]
|
|
52
|
+
referenced_commits: set[str]
|
|
53
|
+
found_new_contributors: dict[str, int | None]
|
|
54
|
+
bullet_count: int
|
|
55
|
+
errors: list[str]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def build_validation_context(
|
|
59
|
+
notes: ReleaseNotes, include_internal: bool = False
|
|
60
|
+
) -> ValidationContext:
|
|
61
|
+
"""Build the reference and section metadata used for validation."""
|
|
62
|
+
del include_internal # Coverage should include every candidate the release may cite.
|
|
63
|
+
|
|
64
|
+
reference_authors: dict[str, str] = {}
|
|
65
|
+
reference_order: list[str] = []
|
|
66
|
+
expected_new_contributors = {
|
|
67
|
+
contributor.username: contributor.first_pr for contributor in notes.new_contributors
|
|
68
|
+
}
|
|
69
|
+
change_section_headings = {
|
|
70
|
+
f"### {CATEGORIES[category]['emoji']} {CATEGORIES[category]['title']}"
|
|
71
|
+
for category in CATEGORIES
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for category in REFERENCE_CATEGORY_ORDER:
|
|
75
|
+
for change in notes.changes.get(category, []):
|
|
76
|
+
ref = f"#{change.pr_number}" if change.pr_number else change.sha[:7].lower()
|
|
77
|
+
if ref in reference_authors:
|
|
78
|
+
continue
|
|
79
|
+
reference_authors[ref] = change.author
|
|
80
|
+
reference_order.append(ref)
|
|
81
|
+
|
|
82
|
+
return ValidationContext(
|
|
83
|
+
reference_authors=reference_authors,
|
|
84
|
+
reference_order=reference_order,
|
|
85
|
+
change_section_headings=change_section_headings,
|
|
86
|
+
expected_new_contributors=expected_new_contributors,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _extract_explicit_references(text: str) -> list[str]:
|
|
91
|
+
refs = [f"#{match}" for match in PR_REF_PATTERN.findall(text)]
|
|
92
|
+
refs.extend(match.lower() for match in COMMIT_REF_PATTERN.findall(text))
|
|
93
|
+
|
|
94
|
+
deduped: list[str] = []
|
|
95
|
+
for ref in refs:
|
|
96
|
+
if ref not in deduped:
|
|
97
|
+
deduped.append(ref)
|
|
98
|
+
return deduped
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _scan_reference_mentions(markdown: str, context: ValidationContext) -> MentionScanResult:
|
|
102
|
+
current_heading = ""
|
|
103
|
+
covered_refs: set[str] = set()
|
|
104
|
+
referenced_prs: set[int] = set()
|
|
105
|
+
referenced_authors: set[str] = set()
|
|
106
|
+
referenced_commits: set[str] = set()
|
|
107
|
+
found_new_contributors: dict[str, int | None] = {}
|
|
108
|
+
errors: list[str] = []
|
|
109
|
+
bullet_count = 0
|
|
110
|
+
|
|
111
|
+
for raw_line in markdown.splitlines():
|
|
112
|
+
line = raw_line.strip()
|
|
113
|
+
if line.startswith("### "):
|
|
114
|
+
current_heading = line
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
if not line.startswith("- "):
|
|
118
|
+
continue
|
|
119
|
+
|
|
120
|
+
refs = _extract_explicit_references(line)
|
|
121
|
+
is_change_bullet = current_heading in context.change_section_headings
|
|
122
|
+
is_new_contributor_bullet = current_heading == NEW_CONTRIBUTORS_HEADING
|
|
123
|
+
|
|
124
|
+
if is_change_bullet:
|
|
125
|
+
bullet_count += 1
|
|
126
|
+
if not refs:
|
|
127
|
+
errors.append(f"Bullet missing explicit PR/commit references: {line}")
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
if is_new_contributor_bullet:
|
|
131
|
+
usernames = USER_HANDLE_PATTERN.findall(line)
|
|
132
|
+
if len(usernames) != 1:
|
|
133
|
+
errors.append(
|
|
134
|
+
"New contributor bullet must mention exactly one contributor handle: "
|
|
135
|
+
f"{line}"
|
|
136
|
+
)
|
|
137
|
+
else:
|
|
138
|
+
username = usernames[0]
|
|
139
|
+
expected_first_pr = context.expected_new_contributors.get(username)
|
|
140
|
+
if username not in context.expected_new_contributors:
|
|
141
|
+
errors.append(f"Unknown new contributor @{username}: {line}")
|
|
142
|
+
elif username in found_new_contributors:
|
|
143
|
+
errors.append(f"Duplicate new contributor @{username}: {line}")
|
|
144
|
+
else:
|
|
145
|
+
found_new_contributors[username] = expected_first_pr
|
|
146
|
+
if expected_first_pr is not None and f"#{expected_first_pr}" not in refs:
|
|
147
|
+
errors.append(
|
|
148
|
+
f"New contributor @{username} must reference #{expected_first_pr}: {line}"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
for ref in refs:
|
|
152
|
+
author = context.reference_authors.get(ref)
|
|
153
|
+
if not author:
|
|
154
|
+
errors.append(f"Bullet references unknown PR/commit {ref}: {line}")
|
|
155
|
+
continue
|
|
156
|
+
if f"@{author}" not in line:
|
|
157
|
+
errors.append(f"Bullet mentioning {ref} is missing @{author}: {line}")
|
|
158
|
+
continue
|
|
159
|
+
|
|
160
|
+
covered_refs.add(ref)
|
|
161
|
+
referenced_authors.add(author)
|
|
162
|
+
if ref.startswith("#"):
|
|
163
|
+
referenced_prs.add(int(ref[1:]))
|
|
164
|
+
else:
|
|
165
|
+
referenced_commits.add(ref)
|
|
166
|
+
|
|
167
|
+
if is_new_contributor_bullet and not refs and context.expected_new_contributors:
|
|
168
|
+
errors.append(f"New contributor bullet missing PR reference: {line}")
|
|
169
|
+
|
|
170
|
+
return MentionScanResult(
|
|
171
|
+
covered_refs=covered_refs,
|
|
172
|
+
referenced_prs=referenced_prs,
|
|
173
|
+
referenced_authors=referenced_authors,
|
|
174
|
+
referenced_commits=referenced_commits,
|
|
175
|
+
found_new_contributors=found_new_contributors,
|
|
176
|
+
bullet_count=bullet_count,
|
|
177
|
+
errors=errors,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def missing_references(
|
|
182
|
+
markdown: str,
|
|
183
|
+
notes: ReleaseNotes,
|
|
184
|
+
include_internal: bool = False,
|
|
185
|
+
) -> list[str]:
|
|
186
|
+
"""Return required refs that are not yet covered in the markdown."""
|
|
187
|
+
context = build_validation_context(notes, include_internal=include_internal)
|
|
188
|
+
scan = _scan_reference_mentions(markdown, context)
|
|
189
|
+
return [ref for ref in context.reference_order if ref not in scan.covered_refs]
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _format_reference_token(ref: str) -> str:
|
|
193
|
+
return ref if ref.startswith("#") else f"({ref})"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def append_reference_coverage_appendix(
|
|
197
|
+
markdown: str,
|
|
198
|
+
notes: ReleaseNotes,
|
|
199
|
+
include_internal: bool = False,
|
|
200
|
+
) -> str:
|
|
201
|
+
"""Append a compact appendix covering any PRs/authors omitted by the agent."""
|
|
202
|
+
context = build_validation_context(notes, include_internal=include_internal)
|
|
203
|
+
scan = _scan_reference_mentions(markdown, context)
|
|
204
|
+
missing_refs = [ref for ref in context.reference_order if ref not in scan.covered_refs]
|
|
205
|
+
if not missing_refs:
|
|
206
|
+
return markdown
|
|
207
|
+
|
|
208
|
+
refs_by_author: dict[str, list[str]] = {}
|
|
209
|
+
author_order: list[str] = []
|
|
210
|
+
for ref in missing_refs:
|
|
211
|
+
author = context.reference_authors[ref]
|
|
212
|
+
if author not in refs_by_author:
|
|
213
|
+
refs_by_author[author] = []
|
|
214
|
+
author_order.append(author)
|
|
215
|
+
refs_by_author[author].append(_format_reference_token(ref))
|
|
216
|
+
|
|
217
|
+
appendix_lines = [COVERAGE_HEADING]
|
|
218
|
+
for author in author_order:
|
|
219
|
+
appendix_lines.append(f"- @{author}: {', '.join(refs_by_author[author])}")
|
|
220
|
+
|
|
221
|
+
base_lines = markdown.rstrip().splitlines()
|
|
222
|
+
for index, line in enumerate(base_lines):
|
|
223
|
+
if line.startswith("**Full Changelog**:"):
|
|
224
|
+
combined = base_lines[:index] + [""] + appendix_lines + [""] + base_lines[index:]
|
|
225
|
+
return "\n".join(combined) + "\n"
|
|
226
|
+
|
|
227
|
+
return "\n".join(base_lines + [""] + appendix_lines + [""])
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def validate_release_notes_markdown(
|
|
231
|
+
markdown: str,
|
|
232
|
+
notes: ReleaseNotes,
|
|
233
|
+
include_internal: bool = False,
|
|
234
|
+
) -> CoverageSummary:
|
|
235
|
+
"""Validate that every included change lists explicit refs and authors."""
|
|
236
|
+
context = build_validation_context(notes, include_internal=include_internal)
|
|
237
|
+
scan = _scan_reference_mentions(markdown, context)
|
|
238
|
+
missing_refs = [ref for ref in context.reference_order if ref not in scan.covered_refs]
|
|
239
|
+
missing_new_contributors = [
|
|
240
|
+
username
|
|
241
|
+
for username in context.expected_new_contributors
|
|
242
|
+
if username not in scan.found_new_contributors
|
|
243
|
+
]
|
|
244
|
+
|
|
245
|
+
errors = list(scan.errors)
|
|
246
|
+
if missing_refs:
|
|
247
|
+
errors.append(
|
|
248
|
+
"Release notes are missing PR/commit coverage for: "
|
|
249
|
+
+ ", ".join(missing_refs)
|
|
250
|
+
)
|
|
251
|
+
if missing_new_contributors:
|
|
252
|
+
errors.append(
|
|
253
|
+
"Release notes are missing new contributor coverage for: "
|
|
254
|
+
+ ", ".join(f"@{username}" for username in missing_new_contributors)
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if errors:
|
|
258
|
+
raise ReleaseNotesValidationError("\n".join(errors))
|
|
259
|
+
|
|
260
|
+
return CoverageSummary(
|
|
261
|
+
bullet_count=scan.bullet_count,
|
|
262
|
+
referenced_prs=sorted(scan.referenced_prs),
|
|
263
|
+
referenced_authors=sorted(scan.referenced_authors),
|
|
264
|
+
referenced_commits=sorted(scan.referenced_commits),
|
|
265
|
+
required_reference_count=len(context.reference_order),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def format_coverage_summary(summary: CoverageSummary) -> str:
|
|
270
|
+
"""Render a compact multi-line validation summary for logs and evidence."""
|
|
271
|
+
prs = ", ".join(f"#{pr}" for pr in summary.referenced_prs) or "none"
|
|
272
|
+
authors = ", ".join(f"@{author}" for author in summary.referenced_authors) or "none"
|
|
273
|
+
commits = ", ".join(summary.referenced_commits) or "none"
|
|
274
|
+
return "\n".join(
|
|
275
|
+
[
|
|
276
|
+
"Release notes attribution coverage validated.",
|
|
277
|
+
f"- Change bullets checked: {summary.bullet_count}",
|
|
278
|
+
f"- Covered references: {len(summary.referenced_prs) + len(summary.referenced_commits)}/{summary.required_reference_count}",
|
|
279
|
+
f"- PRs referenced: {prs}",
|
|
280
|
+
f"- Authors referenced: {authors}",
|
|
281
|
+
f"- Standalone commits referenced: {commits}",
|
|
282
|
+
]
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def parse_args() -> argparse.Namespace:
|
|
287
|
+
"""Parse CLI arguments."""
|
|
288
|
+
parser = argparse.ArgumentParser(
|
|
289
|
+
description="Validate PR and author attribution in generated release notes."
|
|
290
|
+
)
|
|
291
|
+
parser.add_argument(
|
|
292
|
+
"--markdown-file",
|
|
293
|
+
default="release_notes.md",
|
|
294
|
+
help="Path to the generated release notes markdown file.",
|
|
295
|
+
)
|
|
296
|
+
return parser.parse_args()
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def main() -> None:
|
|
300
|
+
"""Validate generated release notes using the same GitHub metadata inputs."""
|
|
301
|
+
args = parse_args()
|
|
302
|
+
token = get_env("GITHUB_TOKEN", required=True)
|
|
303
|
+
tag = get_env("TAG", required=True)
|
|
304
|
+
previous_tag = get_env("PREVIOUS_TAG") or None
|
|
305
|
+
include_internal = get_env("INCLUDE_INTERNAL", "false").lower() == "true"
|
|
306
|
+
repo_name = get_env("REPO_NAME", required=True)
|
|
307
|
+
|
|
308
|
+
notes = generate_release_notes(
|
|
309
|
+
tag=tag,
|
|
310
|
+
previous_tag=previous_tag,
|
|
311
|
+
repo_name=repo_name,
|
|
312
|
+
token=token,
|
|
313
|
+
include_internal=include_internal,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
with open(args.markdown_file) as file:
|
|
317
|
+
markdown = file.read()
|
|
318
|
+
|
|
319
|
+
summary = validate_release_notes_markdown(
|
|
320
|
+
markdown,
|
|
321
|
+
notes,
|
|
322
|
+
include_internal=include_internal,
|
|
323
|
+
)
|
|
324
|
+
print(format_coverage_summary(summary))
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
if __name__ == "__main__":
|
|
328
|
+
main()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Generate Release Notes
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
# Trigger on release tags matching semver pattern
|
|
6
|
+
push:
|
|
7
|
+
tags:
|
|
8
|
+
- 'v[0-9]+.[0-9]+.[0-9]+*'
|
|
9
|
+
|
|
10
|
+
# Allow manual triggering with tag input
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
inputs:
|
|
13
|
+
tag:
|
|
14
|
+
description: 'The release tag to generate notes for'
|
|
15
|
+
required: true
|
|
16
|
+
type: string
|
|
17
|
+
previous-tag:
|
|
18
|
+
description: 'Override automatic detection of previous release tag'
|
|
19
|
+
required: false
|
|
20
|
+
type: string
|
|
21
|
+
include-internal:
|
|
22
|
+
description: 'Include internal/infrastructure changes'
|
|
23
|
+
required: false
|
|
24
|
+
type: boolean
|
|
25
|
+
default: false
|
|
26
|
+
|
|
27
|
+
permissions:
|
|
28
|
+
contents: write
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
generate-release-notes:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- name: Checkout repository
|
|
35
|
+
uses: actions/checkout@v4
|
|
36
|
+
with:
|
|
37
|
+
fetch-depth: 0 # Full history for tag comparison
|
|
38
|
+
|
|
39
|
+
- name: Determine tag
|
|
40
|
+
id: get-tag
|
|
41
|
+
run: |
|
|
42
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
43
|
+
echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
|
|
44
|
+
else
|
|
45
|
+
echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
- name: Generate Release Notes
|
|
49
|
+
id: release-notes
|
|
50
|
+
uses: OpenHands/extensions/plugins/release-notes@main
|
|
51
|
+
with:
|
|
52
|
+
tag: ${{ steps.get-tag.outputs.tag }}
|
|
53
|
+
previous-tag: ${{ github.event.inputs.previous-tag || '' }}
|
|
54
|
+
include-internal: ${{ github.event.inputs.include-internal || 'false' }}
|
|
55
|
+
output-format: release
|
|
56
|
+
llm-api-key: ${{ secrets.LLM_API_KEY }}
|
|
57
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
58
|
+
|
|
59
|
+
- name: Display generated notes
|
|
60
|
+
run: |
|
|
61
|
+
echo "## Release Notes for ${{ steps.get-tag.outputs.tag }}"
|
|
62
|
+
echo ""
|
|
63
|
+
echo "Previous tag: ${{ steps.release-notes.outputs.previous-tag }}"
|
|
64
|
+
echo "Commits: ${{ steps.release-notes.outputs.commit-count }}"
|
|
65
|
+
echo "Contributors: ${{ steps.release-notes.outputs.contributor-count }}"
|
|
66
|
+
echo "New contributors: ${{ steps.release-notes.outputs.new-contributor-count }}"
|
|
67
|
+
echo ""
|
|
68
|
+
echo "---"
|
|
69
|
+
cat release_notes.md
|
|
70
|
+
|
|
71
|
+
- name: Upload release notes artifact
|
|
72
|
+
uses: actions/upload-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: release-notes-${{ steps.get-tag.outputs.tag }}
|
|
75
|
+
path: release_notes.md
|
|
76
|
+
retention-days: 30
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vulnerability-remediation",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Automated security vulnerability scanning and AI-powered remediation. Scans repositories, skips when no issues found, and creates PRs with fixes.",
|
|
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
|
+
"vulnerability",
|
|
15
|
+
"remediation",
|
|
16
|
+
"scanning",
|
|
17
|
+
"automation"
|
|
18
|
+
]
|
|
19
|
+
}
|