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
122 changes: 122 additions & 0 deletions .claude/commands/ci.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
allowed-tools: Bash, Read
---

# /ci — CI-Optimized Verification

Runs the same checks as `/verify-all` but in non-interactive, machine-readable mode. Designed for CI pipelines, pre-merge gates, and automation: no prompts, JSON output, exit code reflects overall pass/fail.

## Usage

```
/ci
/ci --skip script-tests,security
/ci --include shell-syntax,json,pipeline-config,doc-counts
```

The slash command wraps `./scripts/verify-all.sh --ci`. The `--ci` flag implies `--json`, exports `CI=1` and `NO_COLOR=1` to every check, and never reads stdin. Pass `--skip` or `--include` to filter checks; `--root <dir>` points it at another project tree.

## What runs

Same ten checks as `/verify-all`, in the same order:

```
shell-syntax → js-syntax → json → pipeline-config → doc-counts → script-tests
→ types → tests → security → destructive-migrations
```

Checks whose subject is absent skip automatically with a reason: `types`, `tests`, and `security` need an `api/` directory; `destructive-migrations` needs `api/src/db/migrations`; `script-tests` needs a `package.json` with a `test` script and `pnpm` on PATH; any check whose backing script is missing is skipped as `script not found`. Skips never fail the run. No check requires a dev server or a database connection, so all of them run in CI without extra setup.

## Output

JSON written to stdout:

```json
{
"status": "fail",
"checks": [
{ "name": "shell-syntax", "status": "pass", "exitCode": 0, "durationMs": 144 },
{ "name": "js-syntax", "status": "pass", "exitCode": 0, "durationMs": 314 },
{ "name": "json", "status": "pass", "exitCode": 0, "durationMs": 221 },
{ "name": "pipeline-config", "status": "pass", "exitCode": 0, "durationMs": 180 },
{ "name": "doc-counts", "status": "fail", "exitCode": 1, "durationMs": 1466,
"reason": "exit 1",
"command": "bash scripts/check-doc-counts.sh",
"output": "...last 15 lines of the check's output..." },
{ "name": "script-tests", "status": "pass", "exitCode": 0, "durationMs": 8120 },
{ "name": "types", "status": "skip", "exitCode": 0, "durationMs": 0, "reason": "no api/ directory" },
{ "name": "tests", "status": "skip", "exitCode": 0, "durationMs": 0, "reason": "no api/ directory" },
{ "name": "security", "status": "skip", "exitCode": 0, "durationMs": 0, "reason": "no api/ directory" },
{ "name": "destructive-migrations", "status": "skip", "exitCode": 0, "durationMs": 0,
"reason": "no migrations directory at api/src/db/migrations" }
],
"summary": { "passed": 5, "failed": 1, "skipped": 4, "total": 10 }
}
```

| Field | Meaning |
|-------|---------|
| `status` | `"pass"` only when every check passed or was skipped; otherwise `"fail"` |
| `checks[].status` | `pass` \| `fail` \| `skip` |
| `checks[].exitCode` | The exit code returned by the underlying check |
| `checks[].durationMs` | Wall-clock duration (0 for skips) |
| `checks[].reason` | Present on `skip` (why) and `fail` (`exit N`); absent on `pass` |
| `checks[].command` | Present on `fail`: the command to reproduce it |
| `checks[].output` | Present on `fail`: last 15 lines of captured output, ANSI-stripped |
| `summary.passed` / `failed` / `skipped` / `total` | Counts across all checks |

## Steps

### 1. Run the orchestrator in CI mode

```bash
./scripts/verify-all.sh --ci $ARGUMENTS
```

### 2. Surface results to the user

Parse the JSON and report the summary in plain text:

```
5 passed, 1 failed, 4 skipped
Failing: doc-counts (exit 1, 1466ms) — bash scripts/check-doc-counts.sh
```

Include the `output` field of each failing check so the cause is visible without a re-run. When invoked from a CI pipeline, pipe the JSON straight to a downstream step or store it as a build artifact.

### 3. In a GitHub Actions job

```yaml
- run: pnpm install --frozen-lockfile
- run: pnpm verify:ci | tee verify-report.json
- uses: actions/upload-artifact@v4
if: always()
with:
name: verify-report
path: verify-report.json
```

`pnpm verify:ci` propagates the script's exit code, so a failing check fails the job.

## Exit codes

- `0` — every check passed or was skipped
- `1` — one or more checks failed
- `2` — usage error (unknown flag or check name)

The exit code is what CI runners pivot on, so do not swallow it.

## Differences vs `/verify-all`

| Aspect | `/verify-all` | `/ci` |
|--------|---------------|-------|
| Output | Human-readable progress + summary table | JSON to stdout only |
| Failing output | Inline tail under each failure | `output` field per failing check |
| Interactivity | Allowed (no prompts today, but reserved) | Forbidden; `CI=1` exported |
| Use case | Local development | CI pipelines, automation, scripts |
| Exit code on failure | 1 | 1 |

## Related

- `/verify-all` — human-readable version of the same checks
- `./scripts/verify-all.sh --help` — full flag documentation
138 changes: 138 additions & 0 deletions .claude/commands/verify-all.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
allowed-tools: Bash, Read
---

# /verify-all — Run All Local Quality Checks

Runs every local quality check in sequence and reports a pass/fail summary. Wraps `./scripts/verify-all.sh` so you do not have to remember each individual script.

## Purpose

One command that answers "is this checkout healthy?" for both the Nerva framework itself (shell/JS syntax, config JSON, pipeline config, documentation counts, script tests) and a generated API project under `api/` (types, tests, security, migration safety).

## Usage

```
/verify-all
/verify-all --skip script-tests,security
/verify-all --include shell-syntax,json,doc-counts
/verify-all --list
```

Optional flags forward to the underlying script:

| Flag | Effect |
|------|--------|
| `--skip <a,b,c>` | Skip the named checks (comma-separated) |
| `--include <a,b>` | Run only the named checks; everything else is marked skipped |
| `--list` | Print the check names in run order and exit |
| `--root <dir>` | Check a different project tree (defaults to the repo root) |
| `--json` | Emit the machine-readable report instead of the summary table |
| `--help` | Full flag documentation |

Unknown flags and unknown check names exit `2`. For machine-readable output and CI-style behavior, use `/ci` instead.

## What runs

The orchestrator runs these checks in order. Each is independent — a failure in one does not stop the others. Checks whose backing script or subject is absent are **skipped with a reason**, never failed, so the command is safe on a bare framework checkout.

| # | Check | Backing command | What it does | Skipped when |
|---|-------|-----------------|--------------|--------------|
| 1 | `shell-syntax` | `bash -n` | Parses `scripts/*.sh`, `scripts/lib/*.sh`, `.claude/hooks/*.sh` | no shell scripts found |
| 2 | `js-syntax` | `node --check` | Parses `scripts/*.js`, `scripts/lib/*.js` | no JS files / no node |
| 3 | `json` | `JSON.parse` | Parses `.claude/pipeline.config.json`, `.claude/settings.json` (if present), `package.json` | no JSON files / no node |
| 4 | `pipeline-config` | `node scripts/validate-pipeline-config.js` | Validates `pipeline.config.json` against its schema | script not found |
| 5 | `doc-counts` | `scripts/check-doc-counts.sh` | Agent/skill/script/command counts in docs vs disk | script not found |
| 6 | `script-tests` | `pnpm test` | Vitest suite for `scripts/` (slow) | no `package.json` / no `test` script / no pnpm |
| 7 | `types` | `scripts/check-types.sh` | `tsc --noEmit` on the API | no `api/` directory |
| 8 | `tests` | `scripts/run-tests.sh` | Vitest with coverage on the API | no `api/` directory |
| 9 | `security` | `scripts/security-scan.sh` | Dependency audit + anti-pattern scan | no `api/` directory |
| 10 | `destructive-migrations` | `node scripts/check-destructive-migrations.js` | Flags DROP/TRUNCATE/etc. in migrations | no `api/src/db/migrations` |

`api/` is resolved via `NERVA_API_DIR` when set, otherwise `<root>/api`.

## Steps

### 1. Run the orchestrator

```bash
./scripts/verify-all.sh $ARGUMENTS
```

The script prints per-check progress and a summary table at the end:

```
=== verify-all ===

▸ shell-syntax …
✓ pass (144ms)
▸ js-syntax …
✓ pass (314ms)
▸ doc-counts …
✗ fail (exit 1, 1466ms)
--- last 15 lines of output ---
| <file>:<line>: claims <N> scripts, actual <M> -> "<matched text>"
---

=== Summary ===
Check Status Duration Reason
----- ------ -------- ------
shell-syntax pass 144ms
js-syntax pass 314ms
json pass 221ms
pipeline-config pass 180ms
doc-counts fail 1466ms exit 1
script-tests pass 8120ms
types skip 0ms no api/ directory
tests skip 0ms no api/ directory
security skip 0ms no api/ directory
destructive-migrations skip 0ms no migrations directory at api/src/db/migrations

Totals: 5 passed, 1 failed, 4 skipped

✗ Some checks failed. Re-run each failing check individually for full output:
bash scripts/check-doc-counts.sh
```

### 2. If any check fails

The last 15 lines of the failing check's output are shown inline, and the summary lists the exact command to reproduce each failure with full output. Re-run that one script to see the underlying errors:

```bash
bash scripts/check-doc-counts.sh
```

Once the failing check is fixed, re-run `/verify-all` to confirm.

### 3. Skipping the slow check during iteration

`script-tests` runs the whole Vitest suite for `scripts/`. While iterating on something else:

```bash
./scripts/verify-all.sh --skip script-tests
```

## Or use the package scripts

```bash
pnpm verify # same as ./scripts/verify-all.sh
pnpm verify:ci # same as ./scripts/verify-all.sh --ci
```

## Exit codes

- `0` — every check passed (or was skipped)
- `1` — one or more checks failed
- `2` — usage error (unknown flag or check name)

## Common Issues

- **`doc-counts` fails after adding a script/agent/skill/command**: update the counts in `CLAUDE.md`, `README.md`, and any other doc it lists (it prints `file:line`, the claimed number, and the actual number).
- **Everything under `types`/`tests`/`security` is skipped**: there is no `api/` directory yet. Run `./scripts/setup-project.sh` or set `NERVA_API_DIR`.
- **`script-tests` is skipped with "nested verify-all run"**: the orchestrator was invoked from within `pnpm test`; this is the recursion guard, not an error.

## Related

- `/ci` — same checks, JSON output, non-interactive (for automation / CI)
- `/lint` — lint and format only
- `/test` — API tests only
49 changes: 49 additions & 0 deletions .claude/hooks/coverage-check.sh

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading