@activade/open-workflows 1.0.1 → 2.0.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/README.md +91 -64
- package/actions/doc-sync/action.yml +42 -0
- package/actions/doc-sync/skill.md +97 -0
- package/actions/issue-label/action.yml +36 -0
- package/actions/issue-label/skill.md +113 -0
- package/actions/issue-label/src/apply-labels.ts +118 -0
- package/actions/pr-review/action.yml +36 -0
- package/actions/pr-review/skill.md +223 -0
- package/actions/pr-review/src/submit-review.ts +154 -0
- package/actions/release/action.yml +59 -0
- package/actions/release/src/publish.ts +235 -0
- package/dist/cli/index.js +133 -570
- package/package.json +11 -21
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/installer.d.ts +0 -24
- package/dist/cli/templates/auth.d.ts +0 -1
- package/dist/cli/templates/doc-sync.d.ts +0 -1
- package/dist/cli/templates/index.d.ts +0 -7
- package/dist/cli/templates/issue-label.d.ts +0 -1
- package/dist/cli/templates/pr-review.d.ts +0 -1
- package/dist/cli/templates/release.d.ts +0 -1
- package/dist/cli/templates/shared.d.ts +0 -3
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -62
- package/dist/skills/doc-sync.d.ts +0 -1
- package/dist/skills/index.d.ts +0 -10
- package/dist/skills/issue-label.d.ts +0 -1
- package/dist/skills/pr-review.d.ts +0 -1
- package/dist/skills/release-notes.d.ts +0 -1
- package/dist/tools/apply-labels/index.d.ts +0 -2
- package/dist/tools/apply-labels/schema.d.ts +0 -12
- package/dist/tools/bun-release/index.d.ts +0 -2
- package/dist/tools/bun-release/schema.d.ts +0 -4
- package/dist/tools/github-release/index.d.ts +0 -2
- package/dist/tools/github-release/schema.d.ts +0 -9
- package/dist/tools/index.d.ts +0 -2
- package/dist/tools/submit-review/index.d.ts +0 -2
- package/dist/tools/submit-review/schema.d.ts +0 -24
- package/dist/tools/utils/retry.d.ts +0 -7
package/README.md
CHANGED
|
@@ -1,94 +1,121 @@
|
|
|
1
1
|
# open-workflows
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Powered by [OpenCode](https://opencode.ai).
|
|
3
|
+
GitHub automation workflows via composite actions. AI-powered reviews, labeling, and doc sync - plus automated releases with npm provenance.
|
|
6
4
|
|
|
7
5
|
## Quick Start
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
|
-
bunx open-workflows
|
|
8
|
+
bunx @activade/open-workflows
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
The CLI will
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
OPTIONS
|
|
45
|
-
--skills Install skills only
|
|
46
|
-
--workflows Install workflows only
|
|
47
|
-
--version, -v Display version
|
|
48
|
-
--help, -h Display help
|
|
11
|
+
The CLI will prompt you to select workflows and install them to `.github/workflows/`.
|
|
12
|
+
|
|
13
|
+
## Available Actions
|
|
14
|
+
|
|
15
|
+
| Action | AI | Description |
|
|
16
|
+
|--------|-----|-------------|
|
|
17
|
+
| `pr-review` | Yes | AI-powered code reviews |
|
|
18
|
+
| `issue-label` | Yes | Auto-label issues based on content |
|
|
19
|
+
| `doc-sync` | Yes | Keep docs in sync with code changes |
|
|
20
|
+
| `release` | No | Semantic versioning with npm provenance |
|
|
21
|
+
|
|
22
|
+
## Manual Usage
|
|
23
|
+
|
|
24
|
+
### AI-Powered Actions
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
name: PR Review
|
|
28
|
+
on:
|
|
29
|
+
pull_request:
|
|
30
|
+
jobs:
|
|
31
|
+
review:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
permissions:
|
|
34
|
+
contents: read
|
|
35
|
+
pull-requests: write
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: activadee/open-workflows/actions/pr-review@main
|
|
39
|
+
env:
|
|
40
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
49
42
|
```
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
### Release Action (No AI)
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
name: Release
|
|
48
|
+
on:
|
|
49
|
+
workflow_dispatch:
|
|
50
|
+
inputs:
|
|
51
|
+
bump:
|
|
52
|
+
description: 'Version bump'
|
|
53
|
+
required: true
|
|
54
|
+
type: choice
|
|
55
|
+
options: [patch, minor, major]
|
|
56
|
+
jobs:
|
|
57
|
+
release:
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
permissions:
|
|
60
|
+
contents: write
|
|
61
|
+
id-token: write
|
|
62
|
+
steps:
|
|
63
|
+
- uses: actions/checkout@v4
|
|
64
|
+
with:
|
|
65
|
+
fetch-depth: 0
|
|
66
|
+
- uses: activadee/open-workflows/actions/release@main
|
|
67
|
+
with:
|
|
68
|
+
bump: ${{ inputs.bump }}
|
|
69
|
+
env:
|
|
70
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
59
71
|
```
|
|
60
72
|
|
|
61
|
-
|
|
62
|
-
- `submit_review` - Post PR review comments
|
|
63
|
-
- `apply_labels` - Apply labels to issues
|
|
64
|
-
- `github_release` - Create GitHub releases
|
|
65
|
-
- `bun_release` - Publish to npm
|
|
73
|
+
No NPM_TOKEN needed - uses OIDC trusted publishing with provenance.
|
|
66
74
|
|
|
67
|
-
##
|
|
75
|
+
## Authentication
|
|
68
76
|
|
|
69
|
-
|
|
77
|
+
### For AI Actions
|
|
70
78
|
|
|
79
|
+
**Option 1: API Key**
|
|
71
80
|
```bash
|
|
72
81
|
gh secret set ANTHROPIC_API_KEY
|
|
73
82
|
```
|
|
74
83
|
|
|
75
|
-
|
|
84
|
+
**Option 2: Claude Max (OAuth)**
|
|
85
|
+
```bash
|
|
86
|
+
cat ~/.local/share/opencode/auth.json | base64 | gh secret set OPENCODE_AUTH
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## CLI Options
|
|
76
90
|
|
|
77
91
|
```bash
|
|
78
|
-
|
|
92
|
+
bunx @activade/open-workflows [OPTIONS]
|
|
93
|
+
|
|
94
|
+
OPTIONS
|
|
95
|
+
--force, -f Override existing files without prompts
|
|
96
|
+
--version, -v Display version
|
|
97
|
+
--help, -h Display help
|
|
79
98
|
```
|
|
80
99
|
|
|
81
100
|
## How It Works
|
|
82
101
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
102
|
+
**AI Actions (pr-review, issue-label, doc-sync):**
|
|
103
|
+
1. Workflow triggers on GitHub event
|
|
104
|
+
2. Composite action sets up Bun and OpenCode
|
|
105
|
+
3. OpenCode runs with the bundled skill
|
|
106
|
+
4. AI analyzes content and takes action
|
|
107
|
+
|
|
108
|
+
**Release Action:**
|
|
109
|
+
1. Manually triggered with version bump type
|
|
110
|
+
2. Generates changelog from git commits
|
|
111
|
+
3. Publishes to npm with provenance
|
|
112
|
+
4. Creates GitHub release with notes
|
|
88
113
|
|
|
89
|
-
## Customizing
|
|
114
|
+
## Customizing
|
|
90
115
|
|
|
91
|
-
|
|
116
|
+
Fork this repository and modify:
|
|
117
|
+
- `actions/*/skill.md` - AI behavior for AI-powered actions
|
|
118
|
+
- `actions/release/src/publish.ts` - Release logic
|
|
92
119
|
|
|
93
120
|
## License
|
|
94
121
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: 'Doc Sync'
|
|
2
|
+
description: 'Keep documentation in sync with code changes'
|
|
3
|
+
author: 'activadee'
|
|
4
|
+
|
|
5
|
+
inputs:
|
|
6
|
+
model:
|
|
7
|
+
description: 'Model to use for doc analysis'
|
|
8
|
+
required: false
|
|
9
|
+
default: 'anthropic/claude-sonnet-4-5'
|
|
10
|
+
|
|
11
|
+
runs:
|
|
12
|
+
using: 'composite'
|
|
13
|
+
steps:
|
|
14
|
+
- name: Setup Bun
|
|
15
|
+
uses: oven-sh/setup-bun@v2
|
|
16
|
+
|
|
17
|
+
- name: Setup OpenCode auth
|
|
18
|
+
if: env.OPENCODE_AUTH != ''
|
|
19
|
+
shell: bash
|
|
20
|
+
run: |
|
|
21
|
+
mkdir -p ~/.local/share/opencode
|
|
22
|
+
echo "$OPENCODE_AUTH" | base64 -d > ~/.local/share/opencode/auth.json
|
|
23
|
+
|
|
24
|
+
- name: Configure Git
|
|
25
|
+
shell: bash
|
|
26
|
+
run: |
|
|
27
|
+
git config user.name "github-actions[bot]"
|
|
28
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
29
|
+
|
|
30
|
+
- name: Install skill
|
|
31
|
+
shell: bash
|
|
32
|
+
run: |
|
|
33
|
+
mkdir -p .opencode/skill/doc-sync
|
|
34
|
+
cp "${{ github.action_path }}/skill.md" .opencode/skill/doc-sync/SKILL.md
|
|
35
|
+
|
|
36
|
+
- name: Sync Documentation
|
|
37
|
+
shell: bash
|
|
38
|
+
run: |
|
|
39
|
+
bunx opencode-ai@latest run --model "${{ inputs.model }}" \
|
|
40
|
+
"Load the doc-sync skill and sync documentation for PR ${{ github.event.pull_request.number }}"
|
|
41
|
+
env:
|
|
42
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: doc-sync
|
|
3
|
+
description: Keep documentation in sync with code changes. Analyzes PR diffs and updates relevant docs using native write and bash tools.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What I Do
|
|
8
|
+
|
|
9
|
+
Analyze pull request changes and update documentation to reflect code changes. Uses native OpenCode tools (`write`, `bash`) for file operations and git commits.
|
|
10
|
+
|
|
11
|
+
## Workflow
|
|
12
|
+
|
|
13
|
+
1. **Gather PR context**:
|
|
14
|
+
```bash
|
|
15
|
+
gh pr view <number> --json files,title,body,headRefOid
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. **Create todo list**: One item per changed file using `todowrite`
|
|
19
|
+
|
|
20
|
+
3. **Analyze each file**:
|
|
21
|
+
- Mark todo as `in_progress`
|
|
22
|
+
- Identify user-visible changes (APIs, config, behavior)
|
|
23
|
+
- Note which documentation might need updates
|
|
24
|
+
- Mark todo as `completed`
|
|
25
|
+
|
|
26
|
+
4. **After ALL files analyzed**:
|
|
27
|
+
- Identify affected documentation files
|
|
28
|
+
- Read current content of each doc file
|
|
29
|
+
- Plan minimal, precise updates
|
|
30
|
+
|
|
31
|
+
5. **Update documentation**: Use `write` tool for each file needing changes
|
|
32
|
+
|
|
33
|
+
6. **Commit and push**: Use `bash` tool for git operations
|
|
34
|
+
|
|
35
|
+
## Documentation Scope
|
|
36
|
+
|
|
37
|
+
Check these locations first:
|
|
38
|
+
- `README.md` at repository root
|
|
39
|
+
- Files under `docs/` directory
|
|
40
|
+
- API documentation if present
|
|
41
|
+
- Configuration examples
|
|
42
|
+
- Other markdown files at root
|
|
43
|
+
|
|
44
|
+
## What to Update
|
|
45
|
+
|
|
46
|
+
| Code Change | Documentation Update |
|
|
47
|
+
|-------------|---------------------|
|
|
48
|
+
| New feature | Add documentation |
|
|
49
|
+
| Changed behavior | Update existing docs |
|
|
50
|
+
| Removed feature | Remove or mark deprecated |
|
|
51
|
+
| New config option | Document option and defaults |
|
|
52
|
+
| Changed API | Update examples and usage |
|
|
53
|
+
|
|
54
|
+
## Committing Changes
|
|
55
|
+
|
|
56
|
+
After updating documentation files with `write`, commit using `bash`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git add README.md docs/
|
|
60
|
+
git commit -m "[skip ci] docs: <description of changes>"
|
|
61
|
+
git push
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Important**: The `[skip ci]` prefix prevents infinite workflow loops.
|
|
65
|
+
|
|
66
|
+
## Style Guidelines
|
|
67
|
+
|
|
68
|
+
- Keep documentation concise and accurate
|
|
69
|
+
- Match existing tone and formatting
|
|
70
|
+
- Prefer targeted edits over large rewrites
|
|
71
|
+
- Ensure code examples are syntactically correct
|
|
72
|
+
- Don't invent features not present in the code
|
|
73
|
+
|
|
74
|
+
## No Changes Needed
|
|
75
|
+
|
|
76
|
+
If the existing documentation is already accurate:
|
|
77
|
+
- Do NOT create an empty commit
|
|
78
|
+
- Do NOT call any git commands
|
|
79
|
+
- Simply report that no documentation updates were required
|
|
80
|
+
- Explain briefly why the docs are already correct
|
|
81
|
+
|
|
82
|
+
## Common Mistakes to Avoid
|
|
83
|
+
|
|
84
|
+
- Do NOT update docs unrelated to the PR
|
|
85
|
+
- Do NOT start editing before completing all file analyses
|
|
86
|
+
- Do NOT generate marketing-style or overly verbose content
|
|
87
|
+
- Do NOT change code examples unless the underlying code changed
|
|
88
|
+
- Do NOT duplicate information across multiple files
|
|
89
|
+
- Do NOT commit with an empty file list
|
|
90
|
+
|
|
91
|
+
## Example Workflow
|
|
92
|
+
|
|
93
|
+
1. PR changes `src/config/options.ts` to add new `timeout` option
|
|
94
|
+
2. Analyze: user-visible config change
|
|
95
|
+
3. Check `README.md` and `docs/configuration.md`
|
|
96
|
+
4. Update `docs/configuration.md` with new option description
|
|
97
|
+
5. Commit: `[skip ci] docs: add timeout configuration option`
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: 'Issue Label'
|
|
2
|
+
description: 'AI-powered issue labeling based on content analysis'
|
|
3
|
+
author: 'activadee'
|
|
4
|
+
|
|
5
|
+
inputs:
|
|
6
|
+
model:
|
|
7
|
+
description: 'Model to use for labeling'
|
|
8
|
+
required: false
|
|
9
|
+
default: 'anthropic/claude-haiku-4-5'
|
|
10
|
+
|
|
11
|
+
runs:
|
|
12
|
+
using: 'composite'
|
|
13
|
+
steps:
|
|
14
|
+
- name: Setup Bun
|
|
15
|
+
uses: oven-sh/setup-bun@v2
|
|
16
|
+
|
|
17
|
+
- name: Setup OpenCode auth
|
|
18
|
+
if: env.OPENCODE_AUTH != ''
|
|
19
|
+
shell: bash
|
|
20
|
+
run: |
|
|
21
|
+
mkdir -p ~/.local/share/opencode
|
|
22
|
+
echo "$OPENCODE_AUTH" | base64 -d > ~/.local/share/opencode/auth.json
|
|
23
|
+
|
|
24
|
+
- name: Install skill
|
|
25
|
+
shell: bash
|
|
26
|
+
run: |
|
|
27
|
+
mkdir -p .opencode/skill/issue-label
|
|
28
|
+
cp "${{ github.action_path }}/skill.md" .opencode/skill/issue-label/SKILL.md
|
|
29
|
+
|
|
30
|
+
- name: Label Issue
|
|
31
|
+
shell: bash
|
|
32
|
+
run: |
|
|
33
|
+
bunx opencode-ai@latest run --model "${{ inputs.model }}" \
|
|
34
|
+
"Load the issue-label skill. Scripts are at ${{ github.action_path }}/src/. Label issue ${{ github.event.issue.number }}"
|
|
35
|
+
env:
|
|
36
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: issue-label
|
|
3
|
+
description: Automatically apply appropriate labels to GitHub issues based on content analysis.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What I Do
|
|
8
|
+
|
|
9
|
+
Analyze GitHub issue content and apply up to 3 appropriate labels to help maintainers triage and search issues effectively.
|
|
10
|
+
|
|
11
|
+
## Workflow
|
|
12
|
+
|
|
13
|
+
1. **Fetch issue details**: Get title, body, and existing labels
|
|
14
|
+
```bash
|
|
15
|
+
gh issue view <number> --json title,body,labels
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. **Fetch repository labels**: List available labels
|
|
19
|
+
```bash
|
|
20
|
+
gh label list --json name,description,color
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
3. **Analyze the issue**:
|
|
24
|
+
- Determine the main type: bug, feature, documentation, question, etc.
|
|
25
|
+
- Look for hints about complexity (good-first-issue candidate?)
|
|
26
|
+
- Match to existing labels
|
|
27
|
+
|
|
28
|
+
4. **Select labels**: Choose up to 3 existing labels that best describe the issue
|
|
29
|
+
|
|
30
|
+
5. **Create new labels**: Only if no existing labels fit (rare)
|
|
31
|
+
|
|
32
|
+
6. **Apply**: Run the apply-labels script (see Applying Labels section)
|
|
33
|
+
|
|
34
|
+
## Labeling Guidelines
|
|
35
|
+
|
|
36
|
+
### Use Existing Labels
|
|
37
|
+
Prefer existing labels over creating new ones. Check the repository's label taxonomy first.
|
|
38
|
+
|
|
39
|
+
### Common Categories
|
|
40
|
+
- `bug` - Something isn't working
|
|
41
|
+
- `feature` or `feature-request` - New functionality
|
|
42
|
+
- `enhancement` - Improvement to existing feature
|
|
43
|
+
- `documentation` - Docs need updates
|
|
44
|
+
- `question` - Needs clarification
|
|
45
|
+
- `good-first-issue` - Good for newcomers
|
|
46
|
+
|
|
47
|
+
### Label Naming Conventions (for new labels)
|
|
48
|
+
- Lowercase letters only
|
|
49
|
+
- Words separated by hyphens
|
|
50
|
+
- 1-3 words, under 30 characters
|
|
51
|
+
- Example: `needs-reproduction`, `breaking-change`
|
|
52
|
+
|
|
53
|
+
## Applying Labels
|
|
54
|
+
|
|
55
|
+
The script path is provided in your task message. Run the apply-labels script:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
bun "<script_path>/apply-labels.ts" \
|
|
59
|
+
--repo "owner/repo" \
|
|
60
|
+
--issue 123 \
|
|
61
|
+
--labels "bug,needs-triage" \
|
|
62
|
+
--explanation "Issue describes broken functionality in auth module"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Arguments
|
|
66
|
+
|
|
67
|
+
| Argument | Required | Description |
|
|
68
|
+
|----------|----------|-------------|
|
|
69
|
+
| `--repo` | Yes | Repository in owner/repo format |
|
|
70
|
+
| `--issue` | Yes | Issue number |
|
|
71
|
+
| `--labels` | Yes | Comma-separated label names (max 3) |
|
|
72
|
+
| `--explanation` | Yes | Brief reason for label choices |
|
|
73
|
+
| `--new-labels` | No | JSON array of new labels to create first |
|
|
74
|
+
|
|
75
|
+
### Creating New Labels
|
|
76
|
+
|
|
77
|
+
If you need to create new labels (use sparingly):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
bun "<script_path>/apply-labels.ts" \
|
|
81
|
+
--repo "owner/repo" \
|
|
82
|
+
--issue 123 \
|
|
83
|
+
--labels "bug,needs-reproduction" \
|
|
84
|
+
--explanation "Bug report lacking steps to reproduce" \
|
|
85
|
+
--new-labels '[{"name":"needs-reproduction","color":"d93f0b","description":"Issue needs steps to reproduce"}]'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Color is a hex string WITHOUT the leading `#`.
|
|
89
|
+
|
|
90
|
+
## Decision Process
|
|
91
|
+
|
|
92
|
+
1. **Read the issue carefully** - title and full body
|
|
93
|
+
2. **Identify the primary type** - bug? feature? question?
|
|
94
|
+
3. **Check for secondary aspects** - affects docs? good for beginners?
|
|
95
|
+
4. **Match to existing labels** - prefer exact matches
|
|
96
|
+
5. **If no match exists** - consider if a new label is truly needed
|
|
97
|
+
6. **Write explanation** - brief justification for choices
|
|
98
|
+
|
|
99
|
+
## Common Mistakes to Avoid
|
|
100
|
+
|
|
101
|
+
- Do NOT apply more than 3 labels total
|
|
102
|
+
- Do NOT create many highly specific labels unlikely to be reused
|
|
103
|
+
- Do NOT apply labels that contradict the issue content
|
|
104
|
+
- Do NOT overuse broad labels like `question` when specific ones exist
|
|
105
|
+
- Do NOT create duplicate labels with slight name variations
|
|
106
|
+
- Do NOT omit the explanation argument
|
|
107
|
+
- Do NOT run the script more than once
|
|
108
|
+
|
|
109
|
+
## Example Explanation
|
|
110
|
+
|
|
111
|
+
Good: "Labeled as bug and documentation based on steps to reproduce and mention of incorrect docs"
|
|
112
|
+
|
|
113
|
+
Bad: "Applied some labels"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/// <reference types="bun-types" />
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Usage: bun apply-labels.ts --repo owner/repo --issue 123 --labels "bug,enhancement" \
|
|
6
|
+
* --explanation "Why these labels" [--new-labels '[{"name":"x","color":"fff","description":"..."}]']
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { parseArgs } from "util";
|
|
10
|
+
|
|
11
|
+
interface NewLabel {
|
|
12
|
+
name: string;
|
|
13
|
+
color: string;
|
|
14
|
+
description: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
|
|
18
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
19
|
+
try {
|
|
20
|
+
return await fn();
|
|
21
|
+
} catch (error) {
|
|
22
|
+
const isLast = attempt === maxRetries - 1;
|
|
23
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
24
|
+
const isRetryable = msg.includes('rate limit') || msg.includes('timeout') ||
|
|
25
|
+
msg.includes('503') || msg.includes('ECONNRESET');
|
|
26
|
+
if (isLast || !isRetryable) throw error;
|
|
27
|
+
await new Promise(r => setTimeout(r, 1000 * Math.pow(2, attempt)));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
throw new Error('Max retries exceeded');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
const { values } = parseArgs({
|
|
35
|
+
args: Bun.argv.slice(2),
|
|
36
|
+
options: {
|
|
37
|
+
repo: { type: 'string' },
|
|
38
|
+
issue: { type: 'string' },
|
|
39
|
+
labels: { type: 'string' },
|
|
40
|
+
explanation: { type: 'string' },
|
|
41
|
+
'new-labels': { type: 'string' },
|
|
42
|
+
},
|
|
43
|
+
strict: true,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const { repo, issue, labels, explanation, 'new-labels': newLabelsJson } = values;
|
|
47
|
+
|
|
48
|
+
if (!repo || !issue || !labels || !explanation) {
|
|
49
|
+
console.error('Missing required arguments: --repo, --issue, --labels, --explanation');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const issueNumber = parseInt(issue, 10);
|
|
54
|
+
if (isNaN(issueNumber)) {
|
|
55
|
+
console.error('Invalid issue number');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const labelList = labels.split(',').map(l => l.trim()).filter(Boolean);
|
|
60
|
+
if (labelList.length === 0) {
|
|
61
|
+
console.error('No labels provided');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (labelList.length > 3) {
|
|
66
|
+
console.error('Maximum 3 labels allowed');
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const results: string[] = [];
|
|
71
|
+
|
|
72
|
+
if (newLabelsJson) {
|
|
73
|
+
let newLabels: NewLabel[] = [];
|
|
74
|
+
try {
|
|
75
|
+
newLabels = JSON.parse(newLabelsJson);
|
|
76
|
+
} catch {
|
|
77
|
+
console.error('Invalid JSON for --new-labels');
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
for (const label of newLabels) {
|
|
82
|
+
try {
|
|
83
|
+
await withRetry(() =>
|
|
84
|
+
Bun.$`gh label create ${label.name} --color ${label.color} --description ${label.description} --repo ${repo}`.quiet()
|
|
85
|
+
);
|
|
86
|
+
results.push(`Created label: ${label.name}`);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
89
|
+
if (msg.includes('already exists') || msg.includes('Conflict')) {
|
|
90
|
+
results.push(`Label already exists: ${label.name}`);
|
|
91
|
+
} else {
|
|
92
|
+
results.push(`Failed to create label "${label.name}": ${msg}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const labelArg = labelList.join(',');
|
|
99
|
+
try {
|
|
100
|
+
await withRetry(() =>
|
|
101
|
+
Bun.$`gh issue edit ${issueNumber} --add-label ${labelArg} --repo ${repo}`.quiet()
|
|
102
|
+
);
|
|
103
|
+
results.push(`Applied labels: ${labelArg}`);
|
|
104
|
+
results.push(`Reason: ${explanation}`);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
107
|
+
results.push(`Failed to apply labels: ${msg}`);
|
|
108
|
+
console.error(results.join('\n'));
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log(results.join('\n'));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
main().catch(err => {
|
|
116
|
+
console.error('Error:', err.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: 'PR Review'
|
|
2
|
+
description: 'AI-powered pull request code review'
|
|
3
|
+
author: 'activadee'
|
|
4
|
+
|
|
5
|
+
inputs:
|
|
6
|
+
model:
|
|
7
|
+
description: 'Model to use for review'
|
|
8
|
+
required: false
|
|
9
|
+
default: 'anthropic/claude-sonnet-4-5'
|
|
10
|
+
|
|
11
|
+
runs:
|
|
12
|
+
using: 'composite'
|
|
13
|
+
steps:
|
|
14
|
+
- name: Setup Bun
|
|
15
|
+
uses: oven-sh/setup-bun@v2
|
|
16
|
+
|
|
17
|
+
- name: Setup OpenCode auth
|
|
18
|
+
if: env.OPENCODE_AUTH != ''
|
|
19
|
+
shell: bash
|
|
20
|
+
run: |
|
|
21
|
+
mkdir -p ~/.local/share/opencode
|
|
22
|
+
echo "$OPENCODE_AUTH" | base64 -d > ~/.local/share/opencode/auth.json
|
|
23
|
+
|
|
24
|
+
- name: Install skill
|
|
25
|
+
shell: bash
|
|
26
|
+
run: |
|
|
27
|
+
mkdir -p .opencode/skill/pr-review
|
|
28
|
+
cp "${{ github.action_path }}/skill.md" .opencode/skill/pr-review/SKILL.md
|
|
29
|
+
|
|
30
|
+
- name: Review PR
|
|
31
|
+
shell: bash
|
|
32
|
+
run: |
|
|
33
|
+
bunx opencode-ai@latest run --model "${{ inputs.model }}" \
|
|
34
|
+
"Load the pr-review skill. Scripts are at ${{ github.action_path }}/src/. Review PR ${{ github.event.pull_request.number }}"
|
|
35
|
+
env:
|
|
36
|
+
GITHUB_TOKEN: ${{ github.token }}
|