nuqs-codemod-runner

Updates your code automatically when you upgrade the nuqs library, fixing old patterns so everything works with the new version.

Installation
Run `npx skills add "https://github.com/pproenca/dot-skills" --skill "nuqs-codemod-runner"` to install this skill, then follow its SKILL.md instructions for my next request.

Paste this into Claude Code, Cursor, or any agent that can run commands.

SKILL.mdShow the author's original SKILL.md
---
name: nuqs-codemod-runner
description: Migrates a nuqs codebase off pre-v2.5 patterns — deprecated `throttleMs`, hand-rolled setTimeout/useState debounce around `useQueryState`, unchecked `parseAsJson` casts, unversioned `nuqs/adapters/react-router` imports, or `ParserBuilder<T>` type references. Scans the repo, produces a dry-run report, asks for confirmation, applies AST codemods, then runs `tsc --noEmit` + the user's lint as a gate. Trigger even if the user only mentions "upgrade nuqs" or "migrate to nuqs v2.5+" without naming the specific patterns — they almost always exist in pre-v2.5 codebases.
---
# nuqs Codemod Runner

Migrate a codebase from pre-v2.5 nuqs patterns to current v2.5–v2.8 idioms. The skill is **read-only by default** — it never modifies files without an explicit confirmation step, and refuses to run on a dirty git working tree.

## When to Apply

Trigger this skill when:
- A user asks to "upgrade nuqs" or "migrate to nuqs 2.x" in a project that already uses nuqs
- You spot any of the 5 legacy patterns during a review (see the codemod table below)
- A `nuqs` version bump in `package.json` from `<2.5` to `>=2.5` is part of the diff
- The user has just installed/updated the [`nuqs` skill](../nuqs/SKILL.md) and wants to bring existing code into line with it

This skill is the **automation companion** to `skills/.curated/nuqs/` — that skill teaches what each correct pattern looks like; this skill rewrites legacy code to match.

## Workflow Overview

```
┌──────────┐    ┌────────────┐    ┌──────────────────┐    ┌───────────┐    ┌────────────┐
│  scan.sh │──▶ │ scan.json  │──▶ │   report.sh      │──▶ │ apply.sh  │──▶ │ verify.sh  │
└──────────┘    └────────────┘    │ (dry-run table)  │    │ (codemods)│    │ (tsc+lint) │
                                  └──────────────────┘    └───────────┘    └────────────┘
                                          │                     ▲                │
                                          ▼                     │                ▼
                                  user reviews ────────────  confirms       on fail: revert
```

1. **`scripts/scan.sh <repo-root>`** — ripgreps every `.ts/.tsx/.js/.jsx` file for the 5 legacy patterns, emits `scan.json` with `{path, line, matchedPattern, snippet, suggestion}`.
2. **`scripts/report.sh`** — renders `scan.json` as a markdown table grouped by codemod, with file paths and before/after pairs. **Show this output to the user verbatim** and ask for explicit confirmation before continuing.
3. **`scripts/apply.sh [--filter <codemod-id>]`** — runs the jscodeshift transforms in `scripts/transforms/`. Refuses to run unless a fresh `scan.json` exists for the current `git HEAD` and the working tree is clean (`--allow-dirty` overrides).
4. **`scripts/verify.sh`** — runs `tsc --noEmit` and `npm run lint` (or the equivalent commands from `config.json`). If anything fails, `git restore` reverts every file the codemod touched.

Run all four sequentially. If the user only wants to scan, stop at step 2.

## The Five Codemods

| ID | Detects | Rewrites to |
|----|---------|-------------|
| `throttle-ms` | `withOptions({ throttleMs: N })` or `setX(v, { throttleMs: N })` | `withOptions({ limitUrlUpdates: throttle(N) })` + adds `throttle` to the `nuqs` import |
| `manual-debounce` | `useState` mirror + `useEffect` + `setTimeout` debounce around a `useQueryState` setter | `withOptions({ limitUrlUpdates: debounce(N) })` + adds `debounce` to the `nuqs` import; deletes the mirror state and effect |
| `unchecked-json-cast` | `parseAsJson<T>()` (no validator) or `parseAsJson((v) => v as T)` | Inserts a `// TODO: validate` type-guard stub or, if Zod is detected in `package.json`, a `parseAsJson(SchemaName.parse)` form |
| `react-router-unversioned` | `from 'nuqs/adapters/react-router'` | `from 'nuqs/adapters/react-router/v6'` (the alias the unversioned import historically pointed at) |
| `parser-builder-type` | type references to `ParserBuilder<T>` from `nuqs` | `SingleParserBuilder<T>` |

See [`references/workflow.md`](references/workflow.md) for the exact AST shapes each codemod matches and the edge cases it deliberately skips.

## Setup

On first run, `config.json` is populated with the user's lint/typecheck commands and a default `min_node_version`. See `_setup_instructions` in `config.json` for what to fill in.

## Risk & Guardrails

This skill is **write-risk** (it modifies source files). Guardrails:

- `apply.sh` aborts if the working tree is dirty (use `git stash` first, or pass `--allow-dirty` after reading [`gotchas.md`](gotchas.md))
- `apply.sh` aborts if `scan.json` is older than 60 minutes or was generated against a different `git HEAD` — re-run `scan.sh`
- The `hooks/hooks.json` PreToolUse matcher blocks any direct `node scripts/transforms/*.js` invocation that bypasses the orchestrator
- `verify.sh` auto-reverts on TS or lint failure via `git restore` over the touched files (recorded in `last-run.json`)

## Related Skills

- [`nuqs`](../nuqs/) — Best-practice reference for nuqs v2.5+. This skill rewrites legacy code; that skill defines the target.

## Gotchas

See [`gotchas.md`](gotchas.md) for failure modes discovered during use.

Ships with 16 supporting files:

  • AGENTS.md
  • config.json
  • gotchas.md
  • hooks/hooks.json
  • metadata.json
  • references/workflow.md
  • scripts/apply.sh
  • scripts/guardrail.sh
  • scripts/report.sh
  • scripts/scan.sh
  • scripts/transforms/manual-debounce.js
  • scripts/transforms/parser-builder-type.js
  • scripts/transforms/react-router-unversioned.js
  • scripts/transforms/throttle-ms.js
  • scripts/transforms/unchecked-json-cast.js
  • scripts/verify.sh

Mirrored from the author's public source. Install counts from the open skills registry.

The systems behind these skills get built for partners every week.

Partner with us