Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
772516e
chore: remove the Airtable migration tooling
JoeKarow Oct 7, 2026
0297f03
chore: remove the netlify dev --live tunnel
JoeKarow Oct 7, 2026
a018df9
build: commit mise.toml and mise.lock as the toolchain
JoeKarow Oct 7, 2026
f6a25d5
build: run the dev loop through mise
JoeKarow Oct 7, 2026
d51af7a
build: add bin/mise, a repo-local mise for contributors without one
JoeKarow Oct 7, 2026
06b408e
feat: add bin/setup, an idempotent first-run wizard
JoeKarow Oct 7, 2026
5ade7f3
build: add an opt-in [daemons.web] with a port per worktree
JoeKarow Oct 7, 2026
860016a
ci: set up Node and pnpm with jdx/mise-action
JoeKarow Oct 7, 2026
4c030f5
build: add usage and pitchfork to mise, with usage specs on tasks tha…
JoeKarow Oct 7, 2026
c768421
build: mark bin/mise as vendored
JoeKarow Oct 7, 2026
06db664
docs: document mise as the toolchain (ADR 0020)
JoeKarow Oct 7, 2026
8b9fdd4
build: keep tools out of bin/mise's .mise/ directory
JoeKarow Oct 7, 2026
2f8e289
docs(mise): pitchfork now comes from [tools]
JoeKarow Oct 7, 2026
cff06f2
build: install node_modules through mise deps before tasks
JoeKarow Oct 7, 2026
dc48fc6
build: add an optional Mailpit daemon and mise run dev --mail
JoeKarow Oct 7, 2026
414c53b
build: share one Mailpit inbox across every checkout
JoeKarow Oct 7, 2026
d688bbb
formatting
JoeKarow Oct 7, 2026
28ebff6
build(mise): run codegen before the test task
JoeKarow Oct 7, 2026
b85fcb5
test: read the pnpm version from its own mise.lock entry
JoeKarow Oct 7, 2026
fdfe949
build(mise): make min_version soft so Netlify's older mise can build
JoeKarow Oct 7, 2026
a8a8bee
fix(setup): honour ZDOTDIR and require curl up front
JoeKarow Oct 7, 2026
9bd21a0
build(mise): rerun resource codegen when loadMdx changes
JoeKarow Oct 7, 2026
0399b70
Merge remote-tracking branch 'origin/main' into feat/mise-onboarding
JoeKarow Oct 13, 2026
55ba23e
Merge remote-tracking branch 'origin/main' into feat/mise-onboarding
JoeKarow Oct 13, 2026
afd0671
fix: fall back to ./bin/mise in the pnpm dev shim
JoeKarow Oct 13, 2026
e78f321
fix: forward flags through the pnpm dev shim
JoeKarow Oct 13, 2026
2ae5bff
fix(setup): activate mise in .bash_profile on macOS
JoeKarow Oct 13, 2026
700aac3
fix(setup): append bash activation to the login file macOS already reads
JoeKarow Oct 13, 2026
695bd4a
build: split local-dev mise config into mise.dev.toml
JoeKarow Oct 13, 2026
084384e
fix: keep knip resolving the dev tasks' binaries after the mise split
JoeKarow Oct 13, 2026
805a7dc
ci: run the checks through mise tasks
JoeKarow Oct 13, 2026
3e8a81f
build: run Netlify's build through a build:deploy mise task
JoeKarow Oct 13, 2026
f756ab3
build: trim package.json to the dev and test shims
JoeKarow Oct 13, 2026
d5c07bd
fix(setup): make the database stage opt-in and non-fatal
JoeKarow Oct 13, 2026
48f5617
fix(setup): stop offering the web daemon
JoeKarow Oct 13, 2026
cc8fefb
docs: write mise run everywhere
JoeKarow Oct 13, 2026
5145209
build: add a devcontainer for Windows and Codespaces
JoeKarow Oct 13, 2026
e317737
docs: rewrite ADR 0020 around mise run and the two config layers
JoeKarow Oct 13, 2026
70e4df2
fix(setup): keep the dev server log when the database stage fails
JoeKarow Oct 13, 2026
309e392
chore: keep ignoring the private Airtable volunteer mapping
JoeKarow Oct 13, 2026
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
19 changes: 19 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "virtualcoffee.io",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers-extra/features/mise:1.0.0": {}
},
"postCreateCommand": "bin/setup --yes",
"forwardPorts": [9000],
"portsAttributes": {
"9000": {
"label": "Site (mise run dev)"
}
},
"customizations": {
"vscode": {
"extensions": ["hverlin.mise-vscode"]
}
}
}
41 changes: 8 additions & 33 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ URL='http://localhost:9000'
# ── Membership database and /admin ────────────────────────────────────────────
#
# The database itself needs no configuration: `netlify dev` starts a local
# Postgres and @netlify/database finds it. Run `pnpm db:migrate` once, then
# `pnpm db:seed` for realistic sample applications.
# Postgres and @netlify/database finds it. Run `mise run db:migrate` once, then
# `mise run db:seed` for realistic sample applications.
#
# Without Slack credentials, run `pnpm db:seed` and pick a test user from the
# Without Slack credentials, run `mise run db:seed` and pick a test user from the
# "Auth DevTools" panel on /admin/sign-in (or /invites/sign-in). Local only:
# deploy previews sign in with real Slack OAuth through production's callback
# (docs/adr/0007).
Expand Down Expand Up @@ -101,8 +101,11 @@ URL='http://localhost:9000'
# GOOGLE_SMTP_USER=joe@virtualcoffee.io
# GMAIL_SERVICE_ACCOUNT_KEY='{"type":"service_account","client_id":"...","private_key":"-----BEGIN PRIVATE KEY-----\n...","client_email":"..."}'
#
# Or point local dev at a locally running SMTP sink instead — e.g. Mailpit
# (https://mailpit.axllent.org/, SMTP on :1025, web UI on :8025). No
# Or point local dev at a locally running SMTP sink instead. `mise run dev
# --mail` does this for you: it reuses or starts one shared Mailpit inbox for
# every checkout at http://localhost:8025 (installed on first use) and sets
# SMTP_HOST and SMTP_PORT=1025, which win over this file. For your own sink, e.g. Mailpit (https://mailpit.axllent.org/,
# SMTP on :1025, web UI on :8025), set them here. No
# credentials needed: GOOGLE_SMTP_USER/GMAIL_SERVICE_ACCOUNT_KEY are not read
# when this is set. Mail is addressed exactly as production would address it
# — nothing leaves the machine. Only a checkout honours it; a deploy ignores
Expand Down Expand Up @@ -159,31 +162,3 @@ URL='http://localhost:9000'
#
# GITHUB_APP_CLIENT_ID=
# GITHUB_APP_PRIVATE_KEY=
#
# One-off Airtable imports and snapshots. Read keys, one per base. The runbook
# for all of these scripts is scripts/airtable/README.md — note that these scripts
# do not read this file, so the key goes on the command line.
#
# Membership base (`scripts/airtable/importMembership.ts`).
#
# MEMBERSHIP_AIRTABLE_API_KEY=token
#
# Public Data and Monthly Challenges bases
# (`scripts/airtable/snapshotChallenges.ts`). The challenge pages read committed
# JSON, so nothing needs this at runtime — it is only here so the snapshot can
# be regenerated.
#
# PUBLIC_AIRTABLE_API_KEY=token
#
# Form Submissions base (`scripts/airtable/importSubmissions.ts`).
#
# FORMS_AIRTABLE_API_KEY=token
#
# That import also stores four historical CoC attachments in Netlify Blobs.
# Locally there is nothing to set: scripts/with-local-netlify.ts supplies a
# store. These two would point the files at the *production* store instead,
# which only pairs with a production database — and the wrapper refuses that
# combination, so leave them unset.
#
# NETLIFY_SITE_ID=
# NETLIFY_AUTH_TOKEN=
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ drizzle/*/snapshot.json linguist-generated
src/data/monthlyChallenges/data/*.json linguist-generated
src/data/podcast/episodes.json linguist-generated
pnpm-lock.yaml linguist-generated

# bin/mise is generated by `mise generate install-script` (docs/adr/0020).
bin/mise linguist-vendored
103 changes: 37 additions & 66 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ concurrency:
permissions:
contents: read

env:
# Empty skips mise.dev.toml (docs/adr/0020): CI installs and runs only what
# mise.toml pins. `interleave` keeps a task's own output unprefixed, which
# the problem matchers and the sed below rely on.
MISE_ENV: ''
MISE_TASK_OUTPUT: interleave

jobs:
format:
name: format
Expand Down Expand Up @@ -44,14 +51,10 @@ jobs:
# The fix is committed through the API, so git itself never pushes.
persist-credentials: false

- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- name: Set up Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .nvmrc
cache: pnpm
# Node (.nvmrc) and pnpm as pinned in mise.toml. The action
# installs with --locked because mise.lock is committed.
- name: Set up mise
uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand All @@ -61,7 +64,7 @@ jobs:
run: |
# Written outside the workspace: anything left in it would be swept
# up by the auto-commit below.
if pnpm exec prettier --check --ignore-unknown . > "$RUNNER_TEMP/prettier-output.txt" 2>&1; then
if mise run -q format --check > "$RUNNER_TEMP/prettier-output.txt" 2>&1; then
echo "needs_fix=false" >> "$GITHUB_OUTPUT"
else
echo "needs_fix=true" >> "$GITHUB_OUTPUT"
Expand All @@ -70,7 +73,7 @@ jobs:

- name: Apply formatting
if: steps.check.outputs.needs_fix == 'true' && env.CAN_AUTOFIX == 'true'
run: pnpm exec prettier --write --ignore-unknown .
run: mise run -q format

# Committed through the GraphQL API rather than the git CLI, because
# GitHub signs API-created commits: they show as Verified and are
Expand Down Expand Up @@ -133,7 +136,7 @@ jobs:
grep '^\[warn\] ' "$RUNNER_TEMP/prettier-output.txt" | grep -v 'Code style issues' | sed 's/^\[warn\] //' || true
echo '```'
echo
echo 'Run `pnpm format` locally and push the result.'
echo 'Run `mise run format` locally and push the result.'
} >> "$GITHUB_STEP_SUMMARY"
exit 1

Expand All @@ -146,33 +149,25 @@ jobs:
with:
persist-credentials: false

- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- name: Set up Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .nvmrc
cache: pnpm
# Node (.nvmrc) and pnpm as pinned in mise.toml. The action
# installs with --locked because mise.lock is committed.
- name: Set up mise
uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1

- name: Install dependencies
run: pnpm install --frozen-lockfile

# src/data/members/{core,members}.ts and src/data/undrawAspectRatios.ts
# are gitignored codegen that the app imports through the @/* alias. Only
# `prebuild` generates them, so lint/typecheck have to do it themselves.
- name: Generate codegen files
run: pnpm codegen

- name: Register ESLint problem matcher
run: echo "::add-matcher::.github/problem-matchers/eslint-stylish.json"

- name: Lint
# The task depends on codegen: the gitignored barrels the app imports
# through the @/* alias have to exist first.
# ESLint's stylish formatter prints absolute paths, which stop
# annotations anchoring to the diff; strip the workspace prefix.
run: |
set -o pipefail
pnpm lint | sed "s|^${GITHUB_WORKSPACE}/||"
mise run -q lint | sed "s|^${GITHUB_WORKSPACE}/||"

typecheck:
name: typecheck
Expand All @@ -183,26 +178,20 @@ jobs:
with:
persist-credentials: false

- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- name: Set up Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .nvmrc
cache: pnpm
# Node (.nvmrc) and pnpm as pinned in mise.toml. The action
# installs with --locked because mise.lock is committed.
- name: Set up mise
uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Generate codegen files
run: pnpm codegen

- name: Register tsc problem matcher
run: echo "::add-matcher::.github/problem-matchers/tsc.json"

# Depends on codegen, like every task below.
- name: Typecheck
run: pnpm typecheck
run: mise run -q typecheck

test:
name: test
Expand All @@ -217,27 +206,18 @@ jobs:
with:
persist-credentials: false

- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- name: Set up Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .nvmrc
cache: pnpm
# Node (.nvmrc) and pnpm as pinned in mise.toml. The action
# installs with --locked because mise.lock is committed.
- name: Set up mise
uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1

- name: Install dependencies
run: pnpm install --frozen-lockfile

# Same reason as lint/typecheck: a test is free to import a module that
# reaches the gitignored codegen through @/*.
- name: Generate codegen files
run: pnpm codegen

# Vitest switches to its github-actions reporter on its own here, so
# failures annotate the diff without a problem matcher.
- name: Test
run: pnpm test:coverage
run: mise run -q test --coverage

# Coverage totals in the job summary, plus a comment on the PR listing
# the changed files' coverage. A fork PR's token can't write a comment,
Expand All @@ -259,24 +239,15 @@ jobs:
with:
persist-credentials: false

- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- name: Set up Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .nvmrc
cache: pnpm
# Node (.nvmrc) and pnpm as pinned in mise.toml. The action
# installs with --locked because mise.lock is committed.
- name: Set up mise
uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1

- name: Install dependencies
run: pnpm install --frozen-lockfile

# Same reason as lint/typecheck: the codegen barrels are gitignored, and
# without them knip reports the imports as unresolved.
- name: Generate codegen files
run: pnpm codegen

# The github-actions reporter emits workflow commands, so findings land
# as inline annotations without a problem matcher.
- name: Knip
run: pnpm knip --reporter github-actions
run: mise run -q knip -- --reporter github-actions
26 changes: 13 additions & 13 deletions .github/workflows/refresh-bot-list.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ on:
permissions:
contents: read

env:
# Empty skips mise.dev.toml (docs/adr/0020). `interleave` keeps a task's
# output unprefixed, so the summary below holds only the generator's words.
MISE_ENV: ''
MISE_TASK_OUTPUT: interleave

jobs:
refresh:
name: Refresh bot list
Expand Down Expand Up @@ -57,14 +63,8 @@ jobs:
# over git — the commit goes through the API — so it is never needed.
persist-credentials: false

- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- name: Set up Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .nvmrc
cache: pnpm
- name: Set up mise
uses: jdx/mise-action@2d8d4cafcbd33be2ea37d2b6f5ad595363d1f1ca # v5.1.1

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand All @@ -73,8 +73,8 @@ jobs:
id: generate
run: |
set -o pipefail
pnpm build-bot-list | tee "$RUNNER_TEMP/summary.txt"
pnpm format > /dev/null
mise run -q bots:build | tee "$RUNNER_TEMP/summary.txt"
mise run -q format > /dev/null
if git diff --quiet -- src/data/bots.ts; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
Expand All @@ -83,7 +83,7 @@ jobs:

- name: Verify matching still holds
if: steps.generate.outputs.changed == 'true'
run: pnpm check-bot-matching
run: mise run -q bots:check

# Committed through the GraphQL API rather than the git CLI, for the same
# reasons as the format job in ci.yml: GitHub signs API-created commits,
Expand Down Expand Up @@ -155,15 +155,15 @@ jobs:
note='Follows a bump of the pin in `.botlist-version.json`.'
else
title='chore(bots): regenerate the drifted bot list'
note='**This is drift, not an upstream bump.** The pin in `.botlist-version.json` has not changed, so `src/data/bots.ts` was out of step with `src/data/botOverrides.ts` — someone changed policy without running `pnpm build-bot-list`.'
note='**This is drift, not an upstream bump.** The pin in `.botlist-version.json` has not changed, so `src/data/bots.ts` was out of step with `src/data/botOverrides.ts` — someone changed policy without running `mise run bots:build`.'
echo "::error::src/data/bots.ts is out of step with botOverrides.ts at the pinned version"
fi

# The summary quotes crawler names and descriptions from upstream, so
# it is third-party text. Write it to a file rather than interpolating
# it into a command line.
{
echo 'Regenerated by `pnpm build-bot-list` from [ai-robots-txt/ai.robots.txt](https://github.com/ai-robots-txt/ai.robots.txt).'
echo 'Regenerated by `mise run bots:build` from [ai-robots-txt/ai.robots.txt](https://github.com/ai-robots-txt/ai.robots.txt).'
echo
echo "$note"
echo
Expand Down
16 changes: 10 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ node_modules
# Local Netlify folder
.netlify

# Repo-local mise (bin/mise): tools, cache, state
.mise/

# testing
/coverage

Expand All @@ -24,18 +27,19 @@ yarn-error.log*
next-env.d.ts
/deno.lock

# generated member barrels (pnpm build-member-files)
# generated member barrels (mise run codegen:members)
/src/data/members/*
!/src/data/members/index.ts
!/src/data/members/index.test.ts

# generated Undraw aspect ratios (pnpm build-undraw-ratios)
# generated Undraw aspect ratios (mise run codegen:undraw)
/src/data/undrawAspectRatios.ts

# generated resource URLs for typedRoutes (pnpm build-resource-paths)
# generated resource URLs for typedRoutes (mise run codegen:resources)
/src/data/resourcePaths.ts

# The reviewed Airtable -> Slack volunteer mapping. A working artefact of one
# migration that pairs real names with Slack member ids; the site never reads it.
# See scripts/airtable/README.md.
# The reviewed Airtable -> Slack volunteer mapping from the finished migration
# pairs real names with Slack member ids. The importer is gone, but local copies
# may remain; keep them out of git.
scripts/airtable/volunteerSlackMapping.json

2 changes: 1 addition & 1 deletion .greptile/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
},
{
"id": "bot-list-generated",
"rule": "src/data/bots.ts is generated from src/data/botOverrides.ts by pnpm build-bot-list and checked in; never hand-edit it.",
"rule": "src/data/bots.ts is generated from src/data/botOverrides.ts by mise run bots:build and checked in; never hand-edit it.",
"scope": [
"src/data/bots.ts",
"src/data/botOverrides.ts",
Expand Down
Loading
Loading