Skip to content

warlock upgrade

warlock upgrade --to <version> applies the code changes an upgrade needs. For every breaking change between the release your app is on and the target, it either edits the code (when the change is mechanical) or lists the place that needs a decision, with file:line and the reason. It also moves every @warlock.js/* dependency in package.json to the target version.

Terminal window
warlock upgrade --from 5.30 --to 5.31.0 --dry-run # show the diff and the review list; write nothing
warlock upgrade --from 5.30 --to 5.31.0 # apply it
warlock upgrade --from 5.30 --to 5.31.0 --json # machine-readable result, for scripts and agents

Pass --from with the release the app is upgrading from. Without it the command reads the installed @warlock.js/core as the starting version, and once the new release is installed (which it is, since the command ships with it) that version is the target itself, so there is nothing to upgrade across and the command stops with an error asking for --from. An app on 5.29 passes --from 5.29 so the 5.30 changes run too.

Then install (the command prints the right install command for your package manager), run the type check and the tests, and work through the review list.

FlagTypeDescription
--tostringVersion to upgrade to: 5.31 or 5.31.0. Required.
--fromstringVersion to upgrade from. Default: the installed @warlock.js/core (then its range), which is already the target once the new release is installed, so pass it.
--dry-runbooleanPrint the unified diff and the review list without writing any file.
--json, -jbooleanPrint the result as JSON (see below).

A codemod runs when the upgrade crosses its release (from < release <= to), so --from 5.30 --to 5.31.0 skips the 5.30 changes. The command reads src/**/*.{ts,tsx}, package.json, .nvmrc and .node-version; it does not boot the app. Exit code 0 means it ran (review items included), 1 means bad arguments or a missing ts-morph.

The codemods edit TypeScript with ts-morph, an optional peer of @warlock.js/core loaded only by this command. Without it the command stops before touching anything and prints the install command, e.g. pnpm add --save-dev ts-morph.

CodemodReleaseEditsLists for review
logger-sync-calls5.30Removes await before log.info/warn/error/debug/success/fatal/log/assert..then() chained on a log call.
request-log-snapshot5.30In custom log channels: context.request.baseRequest.url/method/ip → .url/.method/.ip, .route.path → .route, .route.name → .name.Any other read that is not on the snapshot (methods, headers, …).
head-viewport5.30Removes a hand-written default viewport <meta> next to <Head />.A non-default viewport tag (move it to metadata.viewport).
seal-validate-result5.30—validate() results whose .data is read without an isValid check.
ai-tool-dispatch5.30—ai.agent()/spawnSubAgent() with tools and no toolDispatch.
ai-anthropic-body5.30—providerOptions.anthropic.body setting a reserved key.
ai-finish-reason5.30—switch statements over a finishReason.
node-22-155.31Raises engines.node, .nvmrc and .node-version below 22.15.A Node alias it cannot read.
rate-limit-defaults5.31—src/config/http.ts without a rateLimit (the default now applies).
seal-refine-output5.31—Every .refine() (now runs on validated output).
seal-container-catch5.31—.catch() on v.object/array/record/tuple (now a no-op).
seal-union-output5.31—Every v.union() (now returns the branch’s output).
ai-compaction-opt-in5.31—Agent compaction without afterTokens and summarize.
vite-8-vitest-55.36Raises vite, vitest, @vitest/* and @vitejs/plugin-react in package.json (including overrides/resolutions); rewrites a vitest/runners test runner to TestRunner from vitest.Removed vitest/* entry points, a Vite config esbuild option, object manualChunks.
vitest-inline-project-plugins5.37.1—A lowerStage3Decorators() call repeated inside a Vitest config that declares projects (Vitest 5 projects inherit the root plugins).
warlock-versionseverySets each @warlock.js/* dependency to the target, keeping ^/~/exact.—

Changes with nothing to edit (hashed auth throttle keys, the new image cache layout) are printed under “Plan for”. Each **BREAKING** entry in the package changelogs names its codemod. The upgrade-from-5-29 skill explains every change in detail.

warlock upgrade 5.29.0 → 5.31.0 (dry run: nothing written)
✓ logger-sync-calls (5.30.0) Remove `await` from synchronous log calls — 2 would change
src/app/orders/services/place-order.service.ts:5 removed await before logger.info()
src/app/orders/services/place-order.service.ts:7 removed await before logger.success()
! seal-refine-output (5.31.0) Review `.refine()` callbacks — 1 to review
src/app/users/schema/user.schema.ts:4 `.refine()` now runs on the validated output, …

--json prints { from, to, dryRun, codemods, applied, manual, notes, changedFiles, diff, installHint? }. applied and manual entries carry codemod, file and line; manual entries add the hint and the skill to read.

@warlock.js/web now requires Vite 8 (^8.0.0) and @vitejs/plugin-react 6, and the test kit targets Vitest 5. Move the family together:

Terminal window
npm install --save-dev ts-morph
npx warlock upgrade --from 5.35 --to 5.36.0 --dry-run
npx warlock upgrade --from 5.35 --to 5.36.0
npm install
npx warlock check

The vite-8-vitest-5 step only touches what Vite 8 and Vitest 5 no longer accept: the dependency ranges, a generated src/test-runner.ts that imports VitestTestRunner from vitest/runners, and a vitest/runners import with other names. It lists removed vitest/* entry points, a Vite config esbuild option and object manualChunks for review. See the Upgrading note in the @warlock.js/web changelog.

ESLint and Prettier support was removed in 5.34.0. Oxlint/Oxfmt is the only supported toolchain. --lint eslint and healthCheckers.eslint are removed. Install the new core release and ts-morph, then migrate an existing app:

Terminal window
npm install --save-dev ts-morph
npx warlock upgrade --from 5.33 --to 5.34.0 --dry-run
npx warlock upgrade --from 5.33 --to 5.34.0
npm install
npm run format
npm run lint:check
npx warlock check

The oxc-toolchain-removal step reapplies the preserved 5.33 oxc-toolchain migration when legacy configs, scripts or dependencies remain. Apps upgrading from 5.32 can still use npx warlock upgrade --from 5.32 --to 5.33.0 first. It replaces standard scripts/dependencies, pins TypeScript 7.0.2, updates generated editor settings, removes healthCheckers.eslint and selects Oxlint. A generated .prettierignore becomes .oxfmtignore; Oxfmt scripts read it explicitly.

Literal custom rules are translated without executing the config. Per-folder no-restricted-imports and no-restricted-exports become Oxlint overrides with file/exclusion patterns. Supported @typescript-eslint/* rules become native typescript/* rules (or native base rules). Options are checked against the pinned Oxlint 1.88.0 schema. Type-aware equivalents enable options.typeAware and add oxlint-tsgolint@7.0.2004 to the app’s dev dependencies. unused-imports/no-unused-imports uses no-unused-vars with safe import fixes; Oxlint shares the severity for imports and variables, so differing active severities are reported for review.

Only unsupported rules/options, computed or imported settings, selectors such as no-restricted-syntax, and conflicting existing Oxc rules need manual review. Each finding names its source file:line, rule and affected file patterns. Fully ported lint configs are removed; configs with findings remain for reference until those findings are addressed. Existing Oxc rules are kept on conflict. --dry-run --json reports the same plan without writes. Customized formatting, editor settings and nonstandard scripts can also require review.

Upgrading: new and migrated template configs enable "categories": { "correctness": "error" }. Address the additional diagnostics; existing Oxc configs retain their categories. A real lockfile beside a workspace marker determines the installer: package-lock.json plus pnpm-workspace.yaml without pnpm-lock.yaml now produces npm install.