Skip to content

Commit bb88bf7

Browse files
committed
Merge remote-tracking branch 'upstream/dev' into sandys-dev
# Conflicts: # packages/opencode/src/cli/cmd/auth.ts # packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx # packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
2 parents 6a590d7 + 20c1868 commit bb88bf7

File tree

318 files changed

+62889
-5275
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

318 files changed

+62889
-5275
lines changed

.github/pull_request_template.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### What does this PR do?
2+
3+
### How did you verify your code works?

.github/workflows/duplicate-prs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ jobs:
4444
{
4545
echo "Check for duplicate PRs related to this new PR:"
4646
echo ""
47+
echo "CURRENT_PR_NUMBER: $PR_NUMBER"
48+
echo ""
4749
echo "Title: $(gh pr view "$PR_NUMBER" --json title --jq .title)"
4850
echo ""
4951
echo "Description:"

.github/workflows/nix-desktop.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ on:
99
- "nix/**"
1010
- "packages/app/**"
1111
- "packages/desktop/**"
12+
pull_request:
13+
paths:
14+
- "flake.nix"
15+
- "flake.lock"
16+
- "nix/**"
17+
- "packages/app/**"
18+
- "packages/desktop/**"
1219
workflow_dispatch:
1320

1421
jobs:

.github/workflows/pr-standards.yml

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
name: PR Standards
2+
3+
on:
4+
pull_request_target:
5+
types: [opened, edited, synchronize]
6+
7+
jobs:
8+
check-standards:
9+
if: |
10+
github.event.pull_request.user.login != 'actions-user' &&
11+
github.event.pull_request.user.login != 'opencode' &&
12+
github.event.pull_request.user.login != 'rekram1-node' &&
13+
github.event.pull_request.user.login != 'thdxr' &&
14+
github.event.pull_request.user.login != 'kommander' &&
15+
github.event.pull_request.user.login != 'jayair' &&
16+
github.event.pull_request.user.login != 'fwang' &&
17+
github.event.pull_request.user.login != 'adamdotdevin' &&
18+
github.event.pull_request.user.login != 'iamdavidhill' &&
19+
github.event.pull_request.user.login != 'opencode-agent[bot]'
20+
runs-on: ubuntu-latest
21+
permissions:
22+
pull-requests: write
23+
steps:
24+
- name: Check PR standards
25+
uses: actions/github-script@v7
26+
with:
27+
script: |
28+
const pr = context.payload.pull_request;
29+
const title = pr.title;
30+
31+
async function addLabel(label) {
32+
await github.rest.issues.addLabels({
33+
owner: context.repo.owner,
34+
repo: context.repo.repo,
35+
issue_number: pr.number,
36+
labels: [label]
37+
});
38+
}
39+
40+
async function removeLabel(label) {
41+
try {
42+
await github.rest.issues.removeLabel({
43+
owner: context.repo.owner,
44+
repo: context.repo.repo,
45+
issue_number: pr.number,
46+
name: label
47+
});
48+
} catch (e) {
49+
// Label wasn't present, ignore
50+
}
51+
}
52+
53+
async function comment(marker, body) {
54+
const markerText = `<!-- pr-standards:${marker} -->`;
55+
const { data: comments } = await github.rest.issues.listComments({
56+
owner: context.repo.owner,
57+
repo: context.repo.repo,
58+
issue_number: pr.number
59+
});
60+
61+
const existing = comments.find(c => c.body.includes(markerText));
62+
if (existing) return;
63+
64+
await github.rest.issues.createComment({
65+
owner: context.repo.owner,
66+
repo: context.repo.repo,
67+
issue_number: pr.number,
68+
body: markerText + '\n' + body
69+
});
70+
}
71+
72+
// Step 1: Check title format
73+
// Matches: feat:, feat(scope):, feat (scope):, etc.
74+
const titlePattern = /^(feat|fix|docs|chore|refactor|test)\s*(\([a-zA-Z0-9-]+\))?\s*:/;
75+
const hasValidTitle = titlePattern.test(title);
76+
77+
if (!hasValidTitle) {
78+
await addLabel('needs:title');
79+
await comment('title', `Hey! Your PR title \`${title}\` doesn't follow conventional commit format.
80+
81+
Please update it to start with one of:
82+
- \`feat:\` or \`feat(scope):\` new feature
83+
- \`fix:\` or \`fix(scope):\` bug fix
84+
- \`docs:\` or \`docs(scope):\` documentation changes
85+
- \`chore:\` or \`chore(scope):\` maintenance tasks
86+
- \`refactor:\` or \`refactor(scope):\` code refactoring
87+
- \`test:\` or \`test(scope):\` adding or updating tests
88+
89+
Where \`scope\` is the package name (e.g., \`app\`, \`desktop\`, \`opencode\`).
90+
91+
See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#pr-titles) for details.`);
92+
return;
93+
}
94+
95+
await removeLabel('needs:title');
96+
97+
// Step 2: Check for linked issue (skip for docs/refactor PRs)
98+
const skipIssueCheck = /^(docs|refactor)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title);
99+
if (skipIssueCheck) {
100+
await removeLabel('needs:issue');
101+
console.log('Skipping issue check for docs/refactor PR');
102+
return;
103+
}
104+
const query = `
105+
query($owner: String!, $repo: String!, $number: Int!) {
106+
repository(owner: $owner, name: $repo) {
107+
pullRequest(number: $number) {
108+
closingIssuesReferences(first: 1) {
109+
totalCount
110+
}
111+
}
112+
}
113+
}
114+
`;
115+
116+
const result = await github.graphql(query, {
117+
owner: context.repo.owner,
118+
repo: context.repo.repo,
119+
number: pr.number
120+
});
121+
122+
const linkedIssues = result.repository.pullRequest.closingIssuesReferences.totalCount;
123+
124+
if (linkedIssues === 0) {
125+
await addLabel('needs:issue');
126+
await comment('issue', `Thanks for your contribution!
127+
128+
This PR doesn't have a linked issue. All PRs must reference an existing issue.
129+
130+
Please:
131+
1. Open an issue describing the bug/feature (if one doesn't exist)
132+
2. Add \`Fixes #<number>\` or \`Closes #<number>\` to this PR description
133+
134+
See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#issue-first-policy) for details.`);
135+
return;
136+
}
137+
138+
await removeLabel('needs:issue');
139+
console.log('PR meets all standards');

.github/workflows/publish.yml

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,22 @@ jobs:
177177
cargo tauri --version
178178
179179
- name: Build and upload artifacts
180-
timeout-minutes: 20
181-
uses: tauri-apps/tauri-action@390cbe447412ced1303d35abe75287949e43437a
180+
uses: Wandalen/wretry.action@v3
181+
timeout-minutes: 60
182+
with:
183+
attempt_limit: 3
184+
attempt_delay: 10000
185+
action: tauri-apps/tauri-action@390cbe447412ced1303d35abe75287949e43437a
186+
with: |
187+
projectPath: packages/desktop
188+
uploadWorkflowArtifacts: true
189+
tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }}
190+
args: --target ${{ matrix.settings.target }} --config ./src-tauri/tauri.prod.conf.json --verbose
191+
updaterJsonPreferNsis: true
192+
releaseId: ${{ needs.publish.outputs.release }}
193+
tagName: ${{ needs.publish.outputs.tag }}
194+
releaseAssetNamePattern: opencode-desktop-[platform]-[arch][ext]
195+
releaseDraft: true
182196
env:
183197
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
184198
TAURI_BUNDLER_NEW_APPIMAGE_FORMAT: true
@@ -190,16 +204,6 @@ jobs:
190204
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
191205
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
192206
APPLE_API_KEY_PATH: ${{ runner.temp }}/apple-api-key.p8
193-
with:
194-
projectPath: packages/desktop
195-
uploadWorkflowArtifacts: true
196-
tauriScript: ${{ (contains(matrix.settings.host, 'ubuntu') && 'cargo tauri') || '' }}
197-
args: --target ${{ matrix.settings.target }} --config ./src-tauri/tauri.prod.conf.json --verbose
198-
updaterJsonPreferNsis: true
199-
releaseId: ${{ needs.publish.outputs.release }}
200-
tagName: ${{ needs.publish.outputs.tag }}
201-
releaseAssetNamePattern: opencode-desktop-[platform]-[arch][ext]
202-
releaseDraft: true
203207

204208
publish-release:
205209
needs:

.github/workflows/stats.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}
99

1010
jobs:
1111
stats:
12-
if: github.repository == 'sst/opencode'
12+
if: github.repository == 'anomalyco/opencode'
1313
runs-on: blacksmith-4vcpu-ubuntu-2404
1414
permissions:
1515
contents: write

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ target
2424
# Local dev files
2525
opencode-dev
2626
logs/
27+
*.bun-build

.opencode/agent/duplicate-pr.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ You are a duplicate PR detection agent. When a PR is opened, your job is to sear
1212

1313
Use the github-pr-search tool to search for PRs that might be addressing the same issue or feature.
1414

15+
IMPORTANT: The input will contain a line `CURRENT_PR_NUMBER: NNNN`. This is the current PR number, you should not mark that the current PR as a duplicate of itself.
16+
1517
Search using keywords from the PR title and description. Try multiple searches with different relevant terms.
1618

1719
If you find potential duplicates:
1820

1921
- List them with their titles and URLs
2022
- Briefly explain why they might be related
2123

22-
If no duplicates are found, say so clearly.
24+
If no duplicates are found, say so clearly. BUT ONLY SAY "No duplicate PRs found" (don't say anything else if no dups)
2325

2426
Keep your response concise and actionable.

.opencode/tool/github-pr-search.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export default tool({
4545
}
4646

4747
const prs = result.items as PR[]
48+
49+
if (prs.length === 0) {
50+
return `No other PRs found matching "${args.query}"`
51+
}
52+
4853
const formatted = prs.map((pr) => `${pr.title}\n${pr.html_url}`).join("\n\n")
4954

5055
return `Found ${result.total_count} PRs (showing ${prs.length}):\n\n${formatted}`

CONTRIBUTING.md

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,30 @@ This starts a local dev server at http://localhost:5173 (or similar port shown i
8383

8484
### Running the Desktop App
8585

86-
The desktop app is a native Tauri application that wraps the web UI. To run it:
86+
The desktop app is a native Tauri application that wraps the web UI.
87+
88+
To run the native desktop app:
89+
90+
```bash
91+
bun run --cwd packages/desktop tauri dev
92+
```
93+
94+
This starts the web dev server on http://localhost:1420 and opens the native window.
95+
96+
If you only want the web dev server (no native shell):
8797

8898
```bash
8999
bun run --cwd packages/desktop dev
90100
```
91101

102+
To create a production `dist/` and build the native app bundle:
103+
104+
```bash
105+
bun run --cwd packages/desktop tauri build
106+
```
107+
108+
This runs `bun run --cwd packages/desktop build` automatically via Tauri’s `beforeBuildCommand`.
109+
92110
> [!NOTE]
93111
> Running the desktop app requires additional Tauri dependencies (Rust toolchain, platform-specific libraries). See the [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for setup instructions.
94112
@@ -131,11 +149,63 @@ With that said, you may want to try these methods, as they might work for you.
131149

132150
## Pull Request Expectations
133151

134-
- Try to keep pull requests small and focused.
135-
- Link relevant issue(s) in the description
152+
### Issue First Policy
153+
154+
**All PRs must reference an existing issue.** Before opening a PR, open an issue describing the bug or feature. This helps maintainers triage and prevents duplicate work. PRs without a linked issue may be closed without review.
155+
156+
- Use `Fixes #123` or `Closes #123` in your PR description to link the issue
157+
- For small fixes, a brief issue is fine - just enough context for maintainers to understand the problem
158+
159+
### General Requirements
160+
161+
- Keep pull requests small and focused
136162
- Explain the issue and why your change fixes it
137-
- Avoid having verbose LLM generated PR descriptions
138-
- Before adding new functions or functionality, ensure that such behavior doesn't already exist elsewhere in the codebase.
163+
- Before adding new functionality, ensure it doesn't already exist elsewhere in the codebase
164+
165+
### UI Changes
166+
167+
If your PR includes UI changes, please include screenshots or videos showing the before and after. This helps maintainers review faster and gives you quicker feedback.
168+
169+
### Logic Changes
170+
171+
For non-UI changes (bug fixes, new features, refactors), explain **how you verified it works**:
172+
173+
- What did you test?
174+
- How can a reviewer reproduce/confirm the fix?
175+
176+
### No AI-Generated Walls of Text
177+
178+
Long, AI-generated PR descriptions and issues are not acceptable and may be ignored. Respect the maintainers' time:
179+
180+
- Write short, focused descriptions
181+
- Explain what changed and why in your own words
182+
- If you can't explain it briefly, your PR might be too large
183+
184+
### PR Titles
185+
186+
PR titles should follow conventional commit standards:
187+
188+
- `feat:` new feature or functionality
189+
- `fix:` bug fix
190+
- `docs:` documentation or README changes
191+
- `chore:` maintenance tasks, dependency updates, etc.
192+
- `refactor:` code refactoring without changing behavior
193+
- `test:` adding or updating tests
194+
195+
You can optionally include a scope to indicate which package is affected:
196+
197+
- `feat(app):` feature in the app package
198+
- `fix(desktop):` bug fix in the desktop package
199+
- `chore(opencode):` maintenance in the opencode package
200+
201+
Examples:
202+
203+
- `docs: update contributing guidelines`
204+
- `fix: resolve crash on startup`
205+
- `feat: add dark mode support`
206+
- `feat(app): add dark mode support`
207+
- `fix(desktop): resolve crash on startup`
208+
- `chore: bump dependency versions`
139209

140210
### Style Preferences
141211

0 commit comments

Comments
 (0)