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
3 changes: 3 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"Bash(wget:*)",
"Bash(nc:*)",
"Bash(ssh:*)",
"Bash(git commit --no-verify:*)",
"Bash(git commit -n:*)",
"Bash(git push --no-verify:*)",
"Read(**/.env*)",
"Read(**/.dev.vars)",
"Read(**/.prod.vars)",
Expand Down
20 changes: 20 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh
# Fast checks before every commit; the heavier ones run in pre-push, and CI runs
# all of them again. Enabled by `pnpm install` (the root `prepare` script) or
# `git config core.hooksPath .githooks`. Never bypass with --no-verify: fix the
# failure instead.
#
# format:check and lint read the working tree, not the staged snapshot, so
# unstaged edits can make them pass or fail. Stage everything you mean to commit.
set -eu

pnpm format:check
pnpm lint

# Scan only what is staged, with a local gitleaks (8.19+ for `git --staged`).
# This fails closed: without gitleaks the commit is refused, since the point of
# this hook is to stop a secret before it reaches the remote. CI scans the full
# history through secret-scan.yml from valuecodes/maintain-kit, which pins the
# gitleaks version.
gitleaks git --help >/dev/null 2>&1 || { echo "install gitleaks 8.19+: https://github.com/gitleaks/gitleaks#installing" >&2; exit 2; }
gitleaks git --staged --redact "$(git rev-parse --show-toplevel)"
9 changes: 9 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
# Slower checks before every push; pre-commit already ran format, lint and the
# staged secrets scan. Turbo's cache replays unchanged packages. Build is left
# to CI. Never bypass with --no-verify: fix the failure instead.
set -eu

pnpm typecheck
pnpm test
pnpm knip
24 changes: 24 additions & 0 deletions .github/workflows/maintain-kit-updates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Maintain-kit updates

on:
schedule:
# Weekly on Monday, after the daily dashboard run. An off-peak minute avoids
# the top-of-the-hour queue.
- cron: "17 6 * * 1"
workflow_dispatch:

permissions: {}

jobs:
# Keeps one PR per update kind (Node.js, pnpm, catalog) open for updates on
# the current major. Nothing auto-merges. The PRs are opened with
# GITHUB_TOKEN, so their `pull_request` checks wait for someone with write
# access to approve them in the PR. A called workflow cannot raise the
# caller's token, so the job grants it here.
maintain-kit-updates:
permissions:
contents: write # push the update branches
pull-requests: write # open, edit and close the PRs
actions: write # required by the called job even without ci-workflow
issues: read # link the dashboard issue
uses: valuecodes/maintain-kit/.github/workflows/updates.yml@e5bf1d24a413d9312cd2051c39ef44ddd9358be5 # v1.0.0
5 changes: 0 additions & 5 deletions .npmrc

This file was deleted.

2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24.22.1
26.12.1
44 changes: 32 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ and inside an app use the `~/` alias (`src/*`) to go up the tree.

## Commands

**Prerequisites:** Node.js 24 (exact version in `.nvmrc`), pnpm 12.12.0 (`packageManager` in root `package.json`).
**Prerequisites:** Node.js 26 (exact version in `.nvmrc`), pnpm 12 (exact version in `packageManager` in root `package.json`).

```bash
pnpm install # Install all dependencies
Expand All @@ -63,12 +63,23 @@ configured by the root `knip.jsonc` and exits 0 when clean. Formatting is oxfmt
(Prettier-compatible), configured by the root `.oxfmtrc.jsonc`, which also sorts
imports.

There is no post-edit formatting hook: run `pnpm format` yourself before committing.

There are no git hooks. CI scans the full git history for secrets with the gitleaks
Nothing formats on edit, and the pre-commit hook only checks formatting: run
`pnpm format` yourself before committing.

Git hooks live in `.githooks/` and are plain shell scripts, with no hook manager.
`pnpm install` enables them through the root `prepare` script. The setting goes in
the clone's shared git config, so it covers every worktree, and a branch without
`.githooks/` simply runs no hooks. If you cloned before the hooks existed and have
not run `pnpm install` since, run `git config core.hooksPath .githooks` once.
`pre-commit` runs `format:check`, `lint` and `gitleaks git --staged` with the local
gitleaks (v8.19+). The secrets scan fails closed, so the commit is refused when
gitleaks is not installed. `pre-push` runs `typecheck`, `test` and `knip`. CI still
runs every check. `format:check` and `lint` read the working tree, not the staged
snapshot, so stage everything you mean to commit.

The hook runs whatever gitleaks is installed; CI scans the full git history with the
version pinned in `secret-scan.yml` from `valuecodes/maintain-kit`, so this repo holds
no gitleaks pin; a local `gitleaks git --staged` (gitleaks v8.19+) does the same for
staged changes before a commit.
no gitleaks pin.

CI checks are defined once, in the reusable `.github/workflows/checks.yml`: typecheck,
lint, knip, format:check, test, CodeQL code scanning (`javascript-typescript`),
Expand Down Expand Up @@ -96,9 +107,17 @@ It keeps one issue, **Maintenance dashboard** (label `maintain-kit-dashboard`),
what is due: `catalog:` updates, pnpm (`packageManager`), Node.js (`.nvmrc`) and
`pnpm audit` findings. Like
`minimumReleaseAge`, a release shows up only once it is 14 days old; a Node.js security
release shows up right away and is flagged. It never opens PRs or commits; doing the
updates stays manual. For a Node.js bump, change only `.nvmrc` (the one place that
holds the exact version). The dashboard, secret-scan and workflow-lint callers pin the
release shows up right away and is flagged. It never opens PRs or commits. For a
Node.js bump, change only `.nvmrc` (the one place that holds the exact version).

`maintain-kit-updates.yml` calls the updates workflow from
`valuecodes/maintain-kit` weekly. It keeps one PR per kind open (Node.js, pnpm,
`catalog:`) on a `maintain-kit/<kind>` branch, for updates on the
current major only; majors stay manual. Those PRs are opened with `GITHUB_TOKEN`, so
their `pull_request` checks wait until someone with write access clicks **Approve
workflows to run** in the PR. It needs **Allow GitHub Actions to create and approve
pull requests** turned on under Settings → Actions → General. Nothing auto-merges.
The dashboard, updates, secret-scan and workflow-lint callers pin the
same `valuecodes/maintain-kit` commit, so bump them together.

---
Expand All @@ -107,14 +126,15 @@ same `valuecodes/maintain-kit` commit, so bump them together.

- Keep diffs tight and focused; no drive-by refactors or new tooling without discussion.
- Never commit secrets, credentials, `.env`, `.dev.vars` or `.prod.vars` files.
- Never bypass the git hooks with `--no-verify`; fix the failure instead.
- Add dependencies to the correct workspace with `pnpm --filter <package> add <dep>`.
Every external version lives in the `catalog:` block of `pnpm-workspace.yaml`
and manifests reference it as `catalog:`; `@repo/*` deps stay `workspace:*`.
Update with `pnpm up --latest -r`; `updateConfig.ignoreDependencies` holds
`@types/node` to the `.nvmrc` major, so bump it by hand.
- Every install enforces the supply-chain settings in `pnpm-workspace.yaml`
(`minimumReleaseAge`, `trustPolicy: no-downgrade`) plus pnpm 12's default
`blockExoticSubdeps`. When one fails, investigate: never disable it, and never
exclude a whole package to get past it.
(`minimumReleaseAge`, `trustPolicy: no-downgrade`, `engineStrict`) plus pnpm
12's default `blockExoticSubdeps`. When one fails, investigate: never disable
it, and never exclude a whole package to get past it.
- Run `pnpm typecheck`, `pnpm lint`, `pnpm knip`, `pnpm format:check` and `pnpm test`
before committing. Update docs when architecture or behavior changes.
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,14 @@ flowchart TD

## Development

Requires Node 24 (exact version in `.nvmrc`) and pnpm 12 (see `packageManager`).
Requires Node 26 (exact version in `.nvmrc`) and pnpm 12 (see `packageManager`).

`pnpm install` also turns on the git hooks in `.githooks/`: format, lint and a staged
secrets scan before each commit; typecheck, test and Knip before each push. Committing
needs `gitleaks` v8.19+ on PATH for the staged secrets scan: `brew install gitleaks`
(macOS, Linux and WSL), or unpack the `linux_x64` tarball from the
[releases page](https://github.com/gitleaks/gitleaks/releases) into a directory on
PATH such as `~/.local/bin`.

```sh
pnpm install # install dependencies
Expand All @@ -90,11 +97,7 @@ test, CodeQL, a gitleaks secret scan over the full git history and actionlint +
over the workflow files; the last two run through the reusable `secret-scan.yml` and
`workflow-lint.yml` from `valuecodes/maintain-kit`. `feature.yml` runs them on PRs and
fans them into `all-passed`; `main.yml` runs them on push to `main`, then the `deploy`
job deploys the workers. There are no git hooks: to scan staged changes before a
commit, run `gitleaks git --staged` with gitleaks v8.19+ (`brew install gitleaks` on
macOS, Linux and WSL, or unpack the `linux_x64` tarball from the
[releases page](https://github.com/gitleaks/gitleaks/releases) into a directory on
PATH such as `~/.local/bin`). GitHub settings this relies on:
job deploys the workers. GitHub settings this relies on:

1. **Rules → Rulesets**: the `main` ruleset requires a pull request and the
`all-passed` status check, the only one to list.
Expand All @@ -106,3 +109,7 @@ PATH such as `~/.local/bin`). GitHub settings this relies on:
`.github/dependabot.yml` only bumps the SHA-pinned GitHub Actions monthly.
5. **Issues**: run the `Maintain-kit dashboard` workflow once, then pin the
**Maintenance dashboard** issue it creates.
6. **Actions → General**: turn on **Allow GitHub Actions to create and approve pull
requests**. `maintain-kit-updates.yml` needs it for its weekly update PRs (one
per kind: Node.js, pnpm, `catalog:`). Nothing auto-merges, and each PR's checks
wait until someone approves the workflows to run in the PR.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"license": "MIT",
"type": "module",
"engines": {
"node": "^24.22.1 || >=26.12.1",
"pnpm": ">=12.0.0"
"node": "^24.22.1 || >=26.12.1"
},
"packageManager": "pnpm@12.12.0+sha512.2ee06ac86db554cf384421461220f0e336a487bfd41b2acd04e17a86b1487832fe45e8d1743f7fc52acc77de12d2356b536fedf8229fc483239e40b13d474449",
"scripts": {
Expand All @@ -18,7 +17,8 @@
"format": "oxfmt",
"format:check": "oxfmt --check",
"knip": "knip",
"clean": "turbo run clean"
"clean": "turbo run clean",
"prepare": "git rev-parse --git-dir >/dev/null 2>&1 && git config --local core.hooksPath .githooks || true"
},
"devDependencies": {
"@types/node": "catalog:",
Expand Down
Loading
Loading