Skip to content

Commit e126afd

Browse files
authored
Merge branch 'ocv' into feature/enhance_copy_mode
2 parents ad9b21a + 485a981 commit e126afd

701 files changed

Lines changed: 46475 additions & 12134 deletions

File tree

Some content is hidden

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

.github/TEAM_MEMBERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ R44VC0RP
1414
rekram1-node
1515
RhysSullivan
1616
thdxr
17+
simonklee

.github/VOUCHED.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ adamdotdevin
1212
ariane-emory
1313
-atharvau AI review spamming literally every PR
1414
-borealbytes
15+
-carycooper777
1516
-danieljoshuanazareth
1617
-danieljoshuanazareth
18+
-davidbernat looks to be a clawdbot that spams team and sends super weird emails, doesnt appear to be a real person
1719
edemaine
1820
-florianleibert
1921
fwang
@@ -27,6 +29,7 @@ r44vc0rp
2729
rekram1-node
2830
-ricardo-m-l
2931
-robinmordasiewicz
32+
rubdos
3033
shantur
3134
simonklee
3235
-spider-yamet clawdbot/llm psychosis, spam pinging the team

.github/actions/setup-bun/action.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
name: "Setup Bun"
22
description: "Setup Bun with caching and install dependencies"
3+
inputs:
4+
install-flags:
5+
description: "Additional flags to pass to 'bun install'"
6+
required: false
7+
default: ""
38
runs:
49
using: "composite"
510
steps:
@@ -46,8 +51,8 @@ runs:
4651
# e.g. ./patches/ for standard-openapi
4752
# https://github.com/oven-sh/bun/issues/28147
4853
if [ "$RUNNER_OS" = "Windows" ]; then
49-
bun install --linker hoisted
54+
bun install --linker hoisted ${{ inputs.install-flags }}
5055
else
51-
bun install
56+
bun install ${{ inputs.install-flags }}
5257
fi
5358
shell: bash

.github/ocv-track

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.25
1+
3.29

.github/workflows/pr-standards.yml

Lines changed: 23 additions & 243 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ jobs:
7171
repo: context.repo.repo,
7272
issue_number: pr.number
7373
});
74-
74+
7575
const existing = comments.find(c => c.body.includes(markerText));
7676
if (existing) return;
77-
77+
7878
await github.rest.issues.createComment({
7979
owner: context.repo.owner,
8080
repo: context.repo.repo,
@@ -83,9 +83,28 @@ jobs:
8383
});
8484
}
8585
86+
async function removeComment(marker) {
87+
const markerText = `<!-- pr-standards:${marker} -->`;
88+
const { data: comments } = await github.rest.issues.listComments({
89+
owner: context.repo.owner,
90+
repo: context.repo.repo,
91+
issue_number: pr.number
92+
});
93+
const existing = comments.find(c => c.body.includes(markerText));
94+
if (!existing) return;
95+
await github.rest.issues.deleteComment({
96+
owner: context.repo.owner,
97+
repo: context.repo.repo,
98+
comment_id: existing.id
99+
});
100+
}
101+
102+
await removeLabel('needs:issue');
103+
await removeComment('issue');
104+
86105
// Step 1: Check title format
87106
// Matches: feat:, feat(scope):, feat (scope):, etc.
88-
const titlePattern = /^(feat|fix|docs|chore|refactor|test)\s*(\([a-zA-Z0-9-]+\))?\s*:/;
107+
const titlePattern = /^(feat|fix|docs|chore|refactor|test|ci)\s*(\([a-zA-Z0-9-]+\))?\s*:/;
89108
const hasValidTitle = titlePattern.test(title);
90109
91110
if (!hasValidTitle) {
@@ -99,6 +118,7 @@ jobs:
99118
- \`chore:\` or \`chore(scope):\` maintenance tasks
100119
- \`refactor:\` or \`refactor(scope):\` code refactoring
101120
- \`test:\` or \`test(scope):\` adding or updating tests
121+
- \`ci:\` or \`ci(scope):\` CI and automation changes
102122
103123
Where \`scope\` is the package name (e.g., \`app\`, \`desktop\`, \`opencode\`).
104124
@@ -107,245 +127,5 @@ jobs:
107127
}
108128
109129
await removeLabel('needs:title');
110-
111-
// Step 2: Check for linked issue (skip for docs/refactor/feat PRs)
112-
const skipIssueCheck = /^(docs|refactor|feat)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title);
113-
if (skipIssueCheck) {
114-
await removeLabel('needs:issue');
115-
console.log('Skipping issue check for docs/refactor/feat PR');
116-
return;
117-
}
118-
const query = `
119-
query($owner: String!, $repo: String!, $number: Int!) {
120-
repository(owner: $owner, name: $repo) {
121-
pullRequest(number: $number) {
122-
closingIssuesReferences(first: 1) {
123-
totalCount
124-
}
125-
}
126-
}
127-
}
128-
`;
129-
130-
const result = await github.graphql(query, {
131-
owner: context.repo.owner,
132-
repo: context.repo.repo,
133-
number: pr.number
134-
});
135-
136-
const linkedIssues = result.repository.pullRequest.closingIssuesReferences.totalCount;
137-
138-
if (linkedIssues === 0) {
139-
await addLabel('needs:issue');
140-
await comment('issue', `Thanks for your contribution!
141-
142-
This PR doesn't have a linked issue. All PRs must reference an existing issue.
143-
144-
Please:
145-
1. Open an issue describing the bug/feature (if one doesn't exist)
146-
2. Add \`Fixes #<number>\` or \`Closes #<number>\` to this PR description
147-
148-
See [CONTRIBUTING.md](../blob/dev/CONTRIBUTING.md#issue-first-policy) for details.`);
149-
return;
150-
}
151-
152-
await removeLabel('needs:issue');
153130
console.log('PR meets all standards');
154131
155-
check-compliance:
156-
runs-on: ubuntu-latest
157-
permissions:
158-
contents: read
159-
pull-requests: write
160-
steps:
161-
- name: Check PR template compliance
162-
uses: actions/github-script@v7
163-
with:
164-
script: |
165-
const pr = context.payload.pull_request;
166-
const login = pr.user.login;
167-
168-
// Skip PRs older than Feb 18, 2026 at 6PM EST (Feb 19, 2026 00:00 UTC)
169-
const cutoff = new Date('2026-02-19T00:00:00Z');
170-
const prCreated = new Date(pr.created_at);
171-
if (prCreated < cutoff) {
172-
console.log(`Skipping: PR #${pr.number} was created before cutoff (${prCreated.toISOString()})`);
173-
return;
174-
}
175-
176-
// Check if author is a team member or bot
177-
if (login === 'opencode-agent[bot]') return;
178-
const { data: file } = await github.rest.repos.getContent({
179-
owner: context.repo.owner,
180-
repo: context.repo.repo,
181-
path: '.github/TEAM_MEMBERS',
182-
ref: 'dev'
183-
});
184-
const members = Buffer.from(file.content, 'base64').toString().split('\n').map(l => l.trim()).filter(Boolean);
185-
if (members.includes(login)) {
186-
console.log(`Skipping: ${login} is a team member`);
187-
return;
188-
}
189-
190-
const body = pr.body || '';
191-
const title = pr.title;
192-
const isDocsRefactorOrFeat = /^(docs|refactor|feat)\s*(\([a-zA-Z0-9-]+\))?\s*:/.test(title);
193-
194-
const issues = [];
195-
196-
// Check: template sections exist
197-
const hasWhatSection = /### What does this PR do\?/.test(body);
198-
const hasTypeSection = /### Type of change/.test(body);
199-
const hasVerifySection = /### How did you verify your code works\?/.test(body);
200-
const hasChecklistSection = /### Checklist/.test(body);
201-
const hasIssueSection = /### Issue for this PR/.test(body);
202-
203-
if (!hasWhatSection || !hasTypeSection || !hasVerifySection || !hasChecklistSection || !hasIssueSection) {
204-
issues.push('PR description is missing required template sections. Please use the [PR template](../blob/dev/.github/pull_request_template.md).');
205-
}
206-
207-
// Check: "What does this PR do?" has real content (not just placeholder text)
208-
if (hasWhatSection) {
209-
const whatMatch = body.match(/### What does this PR do\?\s*\n([\s\S]*?)(?=###|$)/);
210-
const whatContent = whatMatch ? whatMatch[1].trim() : '';
211-
const placeholder = 'Please provide a description of the issue';
212-
const onlyPlaceholder = whatContent.includes(placeholder) && whatContent.replace(placeholder, '').replace(/[*\s]/g, '').length < 20;
213-
if (!whatContent || onlyPlaceholder) {
214-
issues.push('"What does this PR do?" section is empty or only contains placeholder text. Please describe your changes.');
215-
}
216-
}
217-
218-
// Check: at least one "Type of change" checkbox is checked
219-
if (hasTypeSection) {
220-
const typeMatch = body.match(/### Type of change\s*\n([\s\S]*?)(?=###|$)/);
221-
const typeContent = typeMatch ? typeMatch[1] : '';
222-
const hasCheckedBox = /- \[x\]/i.test(typeContent);
223-
if (!hasCheckedBox) {
224-
issues.push('No "Type of change" checkbox is checked. Please select at least one.');
225-
}
226-
}
227-
228-
// Check: issue reference (skip for docs/refactor/feat)
229-
if (!isDocsRefactorOrFeat && hasIssueSection) {
230-
const issueMatch = body.match(/### Issue for this PR\s*\n([\s\S]*?)(?=###|$)/);
231-
const issueContent = issueMatch ? issueMatch[1].trim() : '';
232-
const hasIssueRef = /(closes|fixes|resolves)\s+#\d+/i.test(issueContent) || /#\d+/.test(issueContent);
233-
if (!hasIssueRef) {
234-
issues.push('No issue referenced. Please add `Closes #<number>` linking to the relevant issue.');
235-
}
236-
}
237-
238-
// Check: "How did you verify" has content
239-
if (hasVerifySection) {
240-
const verifyMatch = body.match(/### How did you verify your code works\?\s*\n([\s\S]*?)(?=###|$)/);
241-
const verifyContent = verifyMatch ? verifyMatch[1].trim() : '';
242-
if (!verifyContent) {
243-
issues.push('"How did you verify your code works?" section is empty. Please explain how you tested.');
244-
}
245-
}
246-
247-
// Check: checklist boxes are checked
248-
if (hasChecklistSection) {
249-
const checklistMatch = body.match(/### Checklist\s*\n([\s\S]*?)(?=###|$)/);
250-
const checklistContent = checklistMatch ? checklistMatch[1] : '';
251-
const unchecked = (checklistContent.match(/- \[ \]/g) || []).length;
252-
const checked = (checklistContent.match(/- \[x\]/gi) || []).length;
253-
if (checked < 2) {
254-
issues.push('Not all checklist items are checked. Please confirm you have tested locally and have not included unrelated changes.');
255-
}
256-
}
257-
258-
// Helper functions
259-
async function addLabel(label) {
260-
await github.rest.issues.addLabels({
261-
owner: context.repo.owner,
262-
repo: context.repo.repo,
263-
issue_number: pr.number,
264-
labels: [label]
265-
});
266-
}
267-
268-
async function removeLabel(label) {
269-
try {
270-
await github.rest.issues.removeLabel({
271-
owner: context.repo.owner,
272-
repo: context.repo.repo,
273-
issue_number: pr.number,
274-
name: label
275-
});
276-
} catch (e) {}
277-
}
278-
279-
const hasComplianceLabel = pr.labels.some(l => l.name === 'needs:compliance');
280-
281-
if (issues.length > 0) {
282-
// Non-compliant
283-
if (!hasComplianceLabel) {
284-
await addLabel('needs:compliance');
285-
}
286-
287-
const marker = '<!-- issue-compliance -->';
288-
const { data: comments } = await github.rest.issues.listComments({
289-
owner: context.repo.owner,
290-
repo: context.repo.repo,
291-
issue_number: pr.number
292-
});
293-
const existing = comments.find(c => c.body.includes(marker));
294-
295-
const body_text = `${marker}
296-
This PR doesn't fully meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) and [PR template](../blob/dev/.github/pull_request_template.md).
297-
298-
**What needs to be fixed:**
299-
${issues.map(i => `- ${i}`).join('\n')}
300-
301-
Please edit this PR description to address the above within **2 hours**, or it will be automatically closed.
302-
303-
If you believe this was flagged incorrectly, please let a maintainer know.`;
304-
305-
if (existing) {
306-
await github.rest.issues.updateComment({
307-
owner: context.repo.owner,
308-
repo: context.repo.repo,
309-
comment_id: existing.id,
310-
body: body_text
311-
});
312-
} else {
313-
await github.rest.issues.createComment({
314-
owner: context.repo.owner,
315-
repo: context.repo.repo,
316-
issue_number: pr.number,
317-
body: body_text
318-
});
319-
}
320-
321-
console.log(`PR #${pr.number} is non-compliant: ${issues.join(', ')}`);
322-
} else if (hasComplianceLabel) {
323-
// Was non-compliant, now fixed
324-
await removeLabel('needs:compliance');
325-
326-
const { data: comments } = await github.rest.issues.listComments({
327-
owner: context.repo.owner,
328-
repo: context.repo.repo,
329-
issue_number: pr.number
330-
});
331-
const marker = '<!-- issue-compliance -->';
332-
const existing = comments.find(c => c.body.includes(marker));
333-
if (existing) {
334-
await github.rest.issues.deleteComment({
335-
owner: context.repo.owner,
336-
repo: context.repo.repo,
337-
comment_id: existing.id
338-
});
339-
}
340-
341-
await github.rest.issues.createComment({
342-
owner: context.repo.owner,
343-
repo: context.repo.repo,
344-
issue_number: pr.number,
345-
body: 'Thanks for updating your PR! It now meets our contributing guidelines. :+1:'
346-
});
347-
348-
console.log(`PR #${pr.number} is now compliant, label removed`);
349-
} else {
350-
console.log(`PR #${pr.number} is compliant`);
351-
}

.github/workflows/pr-title.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: pr-title
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, reopened, synchronize]
6+
7+
jobs:
8+
check-title:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
steps:
13+
- name: Validate PR title
14+
env:
15+
PR_TITLE: ${{ github.event.pull_request.title }}
16+
run: |
17+
echo "Checking PR title: $PR_TITLE"
18+
19+
if printf '%s\n' "$PR_TITLE" | grep -Eq '^(feat|fix|chore|docs|test|refactor|ci)(\([^)]+\))?: .+'; then
20+
exit 0
21+
fi
22+
23+
echo "::error title=Invalid PR title::PR title must start with feat:, fix:, chore:, docs:, test:, refactor:, or ci:"
24+
exit 1

0 commit comments

Comments
 (0)