Skip to content

decision: drop legacy Node support (16/18, possibly 20) — three dependabot PRs blocked on engine mismatch #686

Description

@Dixter999

Context

Three dependabot PRs were closed back-to-back this week because the project's stated Node support range can't accommodate modern dependency versions. The pattern is becoming structural:

PR Bump Why it was closed
#683 eslint 9.39.4 → 10.5.0 eslint 10 uses util.styleText (Node 20.12+); CI tests Node 18 → TypeError: util.styleText is not a function
#684 @eslint/js 9.39.4 → 10.0.1 Companion of #683 — same root cause
#685 which 5.0.0 → 7.0.0 which@7 declares engines: { node: '^22.22.2 || ^24.15.0 || >=26.0.0' }; our engines: '>=16' would let npm install --engine-strict hard-fail for Node 16/18/20 users

This is no longer a one-off — it's the new baseline. As the ecosystem moves past Node 18, every fresh major bump will hit the same wall, dependabot will keep opening PRs against this gap, and the AI Review Gate will keep flagging the same engine mismatch.

Current state (inconsistent)

// package.json on develop
"engines": {
  "node": ">=16.0.0",
  "npm": ">=8.0.0"
}
# .github/workflows/test.yml
node-version: [18.x, 20.x]

Two problems already exist before any bump:

  1. engines.node claims >=16 but CI doesn't test 16 — Node 16 may already be silently broken.
  2. Both Node versions the matrix tests are now end-of-life upstream:
    • Node 18 EOL: 2025-04-30 (~14 months ago)
    • Node 20 EOL: 2026-04-30 (~2 months ago)
    • Node 22 LTS active through 2027-04-30
    • Node 24 LTS active through 2028

Options

A. Drop Node 16/18, keep Node 20+ (minimal change)

B. Drop everything <22, align with active LTS (recommended)

  • engines.node>=22.0.0
  • CI matrix → [22.x, 24.x]
  • Unblocks: eslint@10, which@7, and the next year of major bumps
  • Risk: anyone on shared infra still pinned to Node 20 LTS can't install ClaudeAutoPM. Counter-risk: that infra is already running EOL Node.

C. Stay on >=16, pin transitive deps below their Node 22+ thresholds (status quo)

  • Don't bump engines, don't touch CI matrix
  • Keep closing dependabot PRs with rationale comments
  • Cost: every major bump becomes a closed PR. Security backports for the major versions we can't take become a manual problem within ~12 months.

Decision criteria

  • Who actually runs ClaudeAutoPM? It's a CLI distributed via npm + a .claude/ install payload — there's no service-style install base. Users are developers running it locally. Realistically, are any of them still on Node 16 or 18?
  • What does the install payload itself require? Does any .claude/ script use Node syntax that breaks on older Node, or is the dependency-on-modern-Node only in dev/test?
  • What do users see if we go strict? npm install -g claude-autopm on Node 18 → error vs. warning. With engines-strict=false (npm default) they get a warning and it still works. With engines-strict=true it fails. Most users default-leave it false.

Acceptance criteria (whichever option wins)

Out of scope (don't bundle)

  • Migrating any deprecated Node APIs in the codebase
  • Rewriting bash scripts in the payload
  • Plugin-level engine bumps for non-Node ecosystems

Closing the three dependabot PRs without this tracking issue means the decision keeps being made implicitly, one PR at a time. Better to call it once and execute.

Metadata

Metadata

Assignees

No one assigned

    Labels

    dependenciesPull requests that update a dependency fileenhancementNew feature or requestepicEpic-level work spanning multiple tasks

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions