Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
version: 2
updates:
- package-ecosystem: bun
directory: "/"
schedule:
interval: weekly
day: monday
time: "08:00"
timezone: "America/New_York"
open-pull-requests-limit: 5
# Wait 14 days after a release before proposing a bump. Avoids dragging in
# day-old versions that get yanked or hot-patched within their first week.
cooldown:
default-days: 14
# Logical groups so related bumps land together. Patterns are matched
# against package names; a package can only belong to one group, so order
# matters (more-specific groups first).
groups:
react:
patterns:
- "react"
- "react-dom"
- "@types/react"
- "@types/react-dom"
content-pipeline:
patterns:
- "remark-*"
- "rehype-*"
- "@next/mdx"
- "@mdx-js/*"
- "react-markdown"
- "velite"
lint-format:
patterns:
- "@biomejs/*"
minor-and-patch:
update-types:
- minor
- patch
labels:
- dependencies

- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
day: monday
time: "08:00"
timezone: "America/New_York"
cooldown:
default-days: 14
groups:
actions:
update-types:
- minor
- patch
- major
labels:
- dependencies
- github-actions
79 changes: 79 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: CI

on:
push:
branches: [main]
pull_request:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

# Least-privilege: this workflow only reads the repo to lint/build/verify; it
# never writes back. Anything that needs write scopes lives in a separate
# workflow with its own scoped permissions.
permissions:
contents: read

jobs:
ci:
name: Lint, build, verify
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.13

# Bun is the package manager and script runner, but Next.js (and tsc)
# run on Node. ubuntu-latest's default Node version drifts; pin via
# .nvmrc so a future GitHub bump can't break the build silently.
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc

- name: Install
run: bun install --frozen-lockfile

- name: Lint + format check
run: bun run check:ci

# Build BEFORE typecheck: the build runs velite (populating .velite/
# which the `#site/content` path alias resolves to) and produces
# next-env.d.ts. tsc fails without these, so order matters here.
- name: Build
run: bun run build

- name: Type check
run: bun run typecheck

- name: Start server
run: |
bun run start > /tmp/server.log 2>&1 &
echo $! > /tmp/server.pid
for i in $(seq 1 30); do
if curl -sf http://localhost:3000 > /dev/null; then
echo "server ready"
exit 0
fi
sleep 1
done
echo "server failed to start in 30s"
cat /tmp/server.log
exit 1

- name: Verify endpoints
run: bun run verify

- name: Stop server
if: always()
run: |
if [ -f /tmp/server.pid ]; then
kill $(cat /tmp/server.pid) 2>/dev/null || true
fi

- name: Server logs (on failure)
if: failure()
run: cat /tmp/server.log || true
51 changes: 51 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Claude

# Responds to @claude mentions in issues, PR descriptions, comments, and reviews.
# Claude reads the surrounding context, can push commits to the PR branch, and
# replies inline.
#
# Required setup (one-time):
# - Repo secret ANTHROPIC_API_KEY (or CLAUDE_CODE_OAUTH_TOKEN) — set in
# Settings → Secrets and variables → Actions.
# - The GitHub App "Claude" installed on the repo, OR the default
# GITHUB_TOKEN with the permissions block below.

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
pull_request_review:
types: [submitted]
issues:
types: [opened, assigned]

concurrency:
group: claude-${{ github.event.issue.number || github.event.pull_request.number }}
cancel-in-progress: false

jobs:
claude:
name: Run Claude
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1

- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
57 changes: 57 additions & 0 deletions .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Dependabot auto-merge

# Auto-enables merge on Dependabot PRs for patch + minor bumps.
# Major bumps stay open for manual review.
#
# Required setup (one-time, in repo settings):
# 1. Settings → General → Pull Requests → "Allow auto-merge" ✓
# 2. (optional but recommended) Branch protection on main with the
# CI status check marked Required. Otherwise merge fires immediately
# without waiting for CI.
#
# Uses pull_request_target rather than pull_request because Dependabot
# PRs are treated as fork PRs by default, so pull_request runs with a
# read-only GITHUB_TOKEN that can't enable auto-merge. pull_request_target
# is safe here because we never check out or run PR-side code — we only
# read metadata from the GitHub API.

on:
pull_request_target:
types: [opened, reopened, synchronize]

permissions:
contents: write
pull-requests: write

jobs:
auto-merge:
name: Enable auto-merge for patch + minor bumps
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
steps:
- name: Get Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Enable auto-merge (patch + minor)
if: |
steps.metadata.outputs.update-type == 'version-update:semver-patch' ||
steps.metadata.outputs.update-type == 'version-update:semver-minor'
run: gh pr merge --auto --squash "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Comment on major bumps
if: steps.metadata.outputs.update-type == 'version-update:semver-major'
run: |
gh pr comment "$PR_URL" --body "🛑 Major version bump — auto-merge skipped, please review manually.

- Package: \`${{ steps.metadata.outputs.dependency-names }}\`
- From: \`${{ steps.metadata.outputs.previous-version }}\`
- To: \`${{ steps.metadata.outputs.new-version }}\`"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22
8 changes: 0 additions & 8 deletions .prettierrc

This file was deleted.

5 changes: 1 addition & 4 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
{
"recommendations": [
"tailwindcss.tailwindcss-intellisense",
"esbenp.prettier-vscode"
]
"recommendations": ["tailwindcss.tailwindcss-intellisense", "biomejs.biome"]
}
13 changes: 3 additions & 10 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit",
"source.removeUnusedImports": "explicit",
"source.organizeImports": "explicit"
"source.fixAll.biome": "explicit"
},
"css.validate": false,
"[css]": {
"editor.formatOnSave": false
},
Expand All @@ -17,8 +13,5 @@
".*ClassName",
"ngClass",
".*Styles"
],
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
]
}
101 changes: 101 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.14/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": true,
"includes": [
"**",
"!src/content",
"!public",
"!bun.lock",
"!.next",
"!.velite",
"!out",
"!build",
"!next-env.d.ts",
"!src/app/globals.css"
]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 80,
"lineEnding": "lf"
},
"javascript": {
"formatter": {
"quoteStyle": "double",
"jsxQuoteStyle": "double",
"trailingCommas": "none",
"arrowParentheses": "always",
"semicolons": "always"
}
},
"css": {
"parser": {
"cssModules": true,
"tailwindDirectives": true
},
"linter": {
"enabled": true
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "off",
"noArrayIndexKey": "off",
"noAssignInExpressions": "off",
"noShadowRestrictedNames": "off"
},
"style": {
"useImportType": "warn",
"noNonNullAssertion": "off",
"noParameterAssign": "off",
"noDescendingSpecificity": "off"
},
"correctness": {
"noUnusedVariables": {
"level": "error",
"options": {
"ignoreRestSiblings": true
}
},
"noUnusedImports": "error",
"useExhaustiveDependencies": "off",
"useHookAtTopLevel": "error"
},
"a11y": {
"useKeyWithClickEvents": "error",
"noStaticElementInteractions": "error",
"useButtonType": "error",
"noSvgWithoutTitle": "error"
},
"complexity": {
"noForEach": "off",
"noUselessFragments": "off"
},
"performance": {
"noImgElement": "off"
},
"security": {
"noDangerouslySetInnerHtml": "off"
}
}
},
"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": "on"
}
}
}
}
Loading