Skip to content

Commit 6dab89d

Browse files
Add GitHub Copilot code review setup and CI workflow (#93)
1 parent 485fc67 commit 6dab89d

File tree

5 files changed

+184
-8
lines changed

5 files changed

+184
-8
lines changed

.github/copilot-instructions.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copilot Code Review Instructions
2+
3+
## Technology Stack
4+
5+
- **Monorepo**: pnpm workspace with backend, frontend, and shared packages
6+
- **Backend**: Bun runtime + Hono framework + Better SQLite3
7+
- **Frontend**: React 19 + Vite 7 + Radix UI + Tailwind CSS 4
8+
- **Validation**: Zod schemas throughout
9+
- **State**: React Query + Zustand
10+
- **Language**: TypeScript (strict mode)
11+
12+
## Code Style Requirements
13+
14+
### Must Flag as Issues
15+
16+
- Any code comments (code must be self-documenting)
17+
- Console.log statements (use structured logging)
18+
- Use of `any` type without justification
19+
- Default exports (named exports only)
20+
- .then() chains (use async/await)
21+
- Unused variables, imports, or dead code
22+
- Direct state mutations in React components
23+
24+
### Import Patterns
25+
26+
- Backend: `import { Hono } from 'hono'`
27+
- Frontend: `import { Button } from '@/components/ui/button'`
28+
- Shared types: `import { ... } from '@opencode-manager/shared'`
29+
30+
### Architecture Patterns
31+
32+
- Backend routes in `backend/src/routes/`
33+
- Backend services in `backend/src/services/`
34+
- Frontend pages in `frontend/src/pages/`
35+
- Shared types/schemas in `shared/src/`
36+
37+
### Quality Standards
38+
39+
- Test coverage: 80% minimum
40+
- DRY: No duplicated logic
41+
- SOLID principles enforced
42+
- YAGNI: No speculative code
43+
- All functions should have single responsibility
44+
45+
### Review Focus Areas
46+
47+
1. TypeScript type safety (no implicit any)
48+
2. Error handling with try/catch
49+
3. React hooks rules compliance
50+
4. Zod validation on API boundaries
51+
5. Consistent async/await usage

.github/pull_request_template.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## Summary
2+
3+
## Type of Change
4+
5+
- [ ] Bug fix
6+
- [ ] New feature
7+
- [ ] Refactor
8+
- [ ] Documentation
9+
10+
## Checklist
11+
12+
- [ ] Code follows project style (no comments, named imports)
13+
- [ ] TypeScript types are properly defined
14+
- [ ] Tests added/updated (80% coverage target)
15+
- [ ] `pnpm lint` passes locally
16+
- [ ] `pnpm typecheck` passes locally

.github/workflows/ci.yml

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [main, dev]
6+
types: [labeled]
7+
pull_request_review:
8+
types: [submitted]
9+
10+
jobs:
11+
check-ready:
12+
name: Check if Ready for CI
13+
runs-on: ubuntu-latest
14+
outputs:
15+
should-run: ${{ steps.check.outputs.run }}
16+
steps:
17+
- name: Check trigger conditions
18+
id: check
19+
run: |
20+
if [[ "${{ github.event_name }}" == "pull_request_review" && "${{ github.event.review.state }}" == "approved" ]]; then
21+
echo "Triggered by PR approval"
22+
echo "run=true" >> $GITHUB_OUTPUT
23+
elif [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.label.name }}" == "ready-for-ci" ]]; then
24+
echo "Triggered by ready-for-ci label"
25+
echo "run=true" >> $GITHUB_OUTPUT
26+
else
27+
echo "Conditions not met, skipping CI"
28+
echo "run=false" >> $GITHUB_OUTPUT
29+
fi
30+
31+
lint:
32+
name: Lint
33+
needs: check-ready
34+
if: needs.check-ready.outputs.should-run == 'true'
35+
runs-on: ubuntu-latest
36+
steps:
37+
- uses: actions/checkout@v4
38+
39+
- uses: pnpm/action-setup@v4
40+
with:
41+
version: 10.28.1
42+
43+
- uses: actions/setup-node@v4
44+
with:
45+
node-version: "22"
46+
cache: "pnpm"
47+
48+
- name: Install dependencies
49+
run: pnpm install --frozen-lockfile
50+
51+
- name: Run linter
52+
run: pnpm lint
53+
54+
typecheck:
55+
name: Type Check
56+
needs: check-ready
57+
if: needs.check-ready.outputs.should-run == 'true'
58+
runs-on: ubuntu-latest
59+
steps:
60+
- uses: actions/checkout@v4
61+
62+
- uses: pnpm/action-setup@v4
63+
with:
64+
version: 10.28.1
65+
66+
- uses: actions/setup-node@v4
67+
with:
68+
node-version: "22"
69+
cache: "pnpm"
70+
71+
- name: Install dependencies
72+
run: pnpm install --frozen-lockfile
73+
74+
- name: Run type check
75+
run: pnpm typecheck
76+
77+
test:
78+
name: Test
79+
needs: check-ready
80+
if: needs.check-ready.outputs.should-run == 'true'
81+
runs-on: ubuntu-latest
82+
steps:
83+
- uses: actions/checkout@v4
84+
85+
- uses: oven-sh/setup-bun@v2
86+
87+
- uses: pnpm/action-setup@v4
88+
with:
89+
version: 10.28.1
90+
91+
- uses: actions/setup-node@v4
92+
with:
93+
node-version: "22"
94+
cache: "pnpm"
95+
96+
- name: Install dependencies
97+
run: pnpm install --frozen-lockfile
98+
99+
- name: Run tests
100+
run: pnpm test

frontend/src/components/message/PromptInput.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ export const PromptInput = forwardRef<PromptInputHandle, PromptInputProps>(funct
146146
onShowModelsDialog,
147147
onShowHelpDialog,
148148
onToggleDetails,
149-
onExportSession
149+
onExportSession,
150+
currentAgent: localMode || undefined
150151
})
151152

152153
const { files: searchResults } = useFileSearch(

frontend/src/hooks/useCommandHandler.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface CommandHandlerProps {
1818
onShowHelpDialog?: () => void
1919
onToggleDetails?: () => boolean
2020
onExportSession?: () => void
21+
currentAgent?: string
2122
}
2223

2324
export function useCommandHandler({
@@ -28,11 +29,12 @@ export function useCommandHandler({
2829
onShowModelsDialog,
2930
onShowHelpDialog,
3031
onToggleDetails,
31-
onExportSession
32+
onExportSession,
33+
currentAgent
3234
}: CommandHandlerProps) {
3335
const navigate = useNavigate()
3436
const createSession = useCreateSession(opcodeUrl, directory)
35-
const { model } = useModelSelection(opcodeUrl, directory)
37+
const { model, modelString } = useModelSelection(opcodeUrl, directory)
3638
const setSessionStatus = useSessionStatus((state) => state.setStatus)
3739
const [loading, setLoading] = useState(false)
3840

@@ -58,7 +60,9 @@ export function useCommandHandler({
5860
case 'themes':
5961
await client.sendCommand(sessionID, {
6062
command: command.name,
61-
arguments: args
63+
arguments: args,
64+
agent: currentAgent,
65+
model: modelString || undefined
6266
})
6367
break
6468

@@ -128,14 +132,18 @@ export function useCommandHandler({
128132
case 'init':
129133
await client.sendCommand(sessionID, {
130134
command: command.name,
131-
arguments: args
135+
arguments: args,
136+
agent: currentAgent,
137+
model: modelString || undefined
132138
})
133139
break
134-
140+
135141
default:
136142
await client.sendCommand(sessionID, {
137143
command: command.name,
138-
arguments: args
144+
arguments: args,
145+
agent: currentAgent,
146+
model: modelString || undefined
139147
})
140148
}
141149
} catch (error) {
@@ -145,7 +153,7 @@ export function useCommandHandler({
145153
} finally {
146154
setLoading(false)
147155
}
148-
}, [sessionID, opcodeUrl, directory, onShowSessionsDialog, onShowModelsDialog, onShowHelpDialog, onToggleDetails, onExportSession, createSession, navigate, model, setSessionStatus])
156+
}, [sessionID, opcodeUrl, directory, onShowSessionsDialog, onShowModelsDialog, onShowHelpDialog, onToggleDetails, onExportSession, createSession, navigate, model, modelString, currentAgent, setSessionStatus])
149157

150158
return {
151159
executeCommand,

0 commit comments

Comments
 (0)