Enforce minimum Bun version 1.3.6 at runtime#334
Conversation
Update engines.bun in package.json from >=1.0.0 to >=1.3.6 and add a runtime version check at CLI startup that exits with a clear error message if the user's Bun version is too old. https://claude.ai/code/session_01RuyCDncNpp7xJoDRLoq8Vt
Move the version comparison logic from cli.tsx into a testable checkBunVersion function in src/utils/validation.ts. Add 10 test cases covering exact match, higher/lower major/minor/patch versions, pre-release metadata stripping, and numeric segment ordering. https://claude.ai/code/session_01RuyCDncNpp7xJoDRLoq8Vt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
WalkthroughAdds Bun runtime version validation: package.json minimum Bun bumped to 1.3.6; new semver comparator and validation utilities; CLI checks Bun.version at startup and exits if running Bun is older; tests added and migration refactor uses shared semver util. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI (startup)
participant Pkg as package.json
participant Val as Validation util
participant Bun as Bun runtime
CLI->>Pkg: read engines.bun (minVersion)
CLI->>Bun: check if Bun exists / get Bun.version
alt Bun present
CLI->>Val: checkBunVersion(Bun.version, minVersion)
Val-->>CLI: null (ok) / errorMessage
alt errorMessage
CLI->>Bun: exit with errorMessage
else ok
CLI->>CLI: continue startup (show help / run commands)
end
else Bun absent
CLI->>CLI: skip Bun validation, continue startup
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (4)
src/utils/validation.ts (2)
6-6: Optional: consider co-locatingcompareSemverStringswith the validation module.
validation.tsis a general-purpose utility, but it now carries a dependency onsetup/migration.ts. Ifmigration.tsis ever split or its exports change, this silent coupling breaks version checks. MovingcompareSemverStringsintovalidation.ts(or a dedicatedsrc/utils/semver.ts) would eliminate the dependency and makemigration.tsthe consumer rather than the source.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/validation.ts` at line 6, validation.ts currently imports compareSemverStrings from setup/migration.js creating an unnecessary coupling; extract the compareSemverStrings implementation into validation.ts (or a new src/utils/semver.ts) and update all imports (e.g., in migration.ts and any other modules) to consume it from the new location so migration.ts becomes a consumer, not the source; ensure exported name stays compareSemverStrings and run/adjust any unit tests or type exports that referenced the old path.
261-264: Consider includingbun upgradein the error message for immediate actionability.The current URL (
https://bun.sh/docs/installation) is an install guide. Users who already have an older Bun installed are better served by the upgrade command directly.bun upgradeis the built-in command for upgrading Bun, and a dedicated upgrade guide is available athttps://bun.com/docs/guides/util/upgrade.💡 Suggested wording
- `Please upgrade: https://bun.sh/docs/installation` + `Please upgrade by running: bun upgrade\n` + + `See also: https://bun.com/docs/guides/util/upgrade`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/validation.ts` around lines 261 - 264, The version-mismatch message that uses minVersion and currentVersion should be updated to include an actionable upgrade hint; in the return statement that builds the string using minVersion and currentVersion (where the code currently returns `ralph-tui requires Bun >= ${minVersion}... Bun ${currentVersion}`), append a suggestion to run `bun upgrade` and include the upgrade guide URL (`https://bun.com/docs/guides/util/upgrade`) alongside or instead of the installation docs so users have an immediate remediation path.src/utils/validation.test.ts (1)
49-61: Consider adding a test for a pre-release version that falls below the minimum.The suite covers
1.3.6-beta(pre-release of the minimum itself) and build metadata, but not1.3.5-beta— a pre-release of a version that is lower than the minimum. The implementation handles it correctly (metadata stripped →1.3.5 < 1.3.6→ error), but an explicit test would document the intended behaviour.+ test('returns error for pre-release version below minimum', () => { + const result = checkBunVersion('1.3.5-beta', MIN_VERSION); + expect(result).not.toBeNull(); + expect(result).toContain('requires Bun >= 1.3.6'); + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/validation.test.ts` around lines 49 - 61, Add a test in src/utils/validation.test.ts that verifies pre-release versions below the minimum produce an error: call checkBunVersion('1.3.5-beta', MIN_VERSION) and assert it is NOT null (or matches the existing error shape). Place it alongside the other tests (e.g., name it "pre-release below minimum returns error") so it documents that '1.3.5-beta' is treated as 1.3.5 and thus fails against MIN_VERSION; reference the checkBunVersion function and MIN_VERSION constant used in the file.src/cli.tsx (1)
28-29:MIN_BUN_VERSIONis a second source of truth alongsidepackage.json.
engines.buninpackage.jsonalready declares>=1.3.6. If the minimum version is bumped in the future, both this constant and the manifest need updating in sync. A brief comment cross-referencingpackage.jsonwould reduce the risk of the two drifting apart.💡 Suggested addition
-/** Minimum bun version required to run ralph-tui. */ +/** Minimum bun version required to run ralph-tui. Keep in sync with engines.bun in package.json. */ const MIN_BUN_VERSION = '1.3.6';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/cli.tsx` around lines 28 - 29, The MIN_BUN_VERSION constant is a second source of truth; update the comment above MIN_BUN_VERSION to explicitly reference the engines.bun entry in package.json (e.g., "See package.json engines.bun for the authoritative minimum") and add a short note to keep both values in sync when bumping versions — alternatively, replace the hardcoded MIN_BUN_VERSION with code that reads engines.bun from package.json at runtime if you prefer a single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/cli.tsx`:
- Around line 28-29: The MIN_BUN_VERSION constant is a second source of truth;
update the comment above MIN_BUN_VERSION to explicitly reference the engines.bun
entry in package.json (e.g., "See package.json engines.bun for the authoritative
minimum") and add a short note to keep both values in sync when bumping versions
— alternatively, replace the hardcoded MIN_BUN_VERSION with code that reads
engines.bun from package.json at runtime if you prefer a single source of truth.
In `@src/utils/validation.test.ts`:
- Around line 49-61: Add a test in src/utils/validation.test.ts that verifies
pre-release versions below the minimum produce an error: call
checkBunVersion('1.3.5-beta', MIN_VERSION) and assert it is NOT null (or matches
the existing error shape). Place it alongside the other tests (e.g., name it
"pre-release below minimum returns error") so it documents that '1.3.5-beta' is
treated as 1.3.5 and thus fails against MIN_VERSION; reference the
checkBunVersion function and MIN_VERSION constant used in the file.
In `@src/utils/validation.ts`:
- Line 6: validation.ts currently imports compareSemverStrings from
setup/migration.js creating an unnecessary coupling; extract the
compareSemverStrings implementation into validation.ts (or a new
src/utils/semver.ts) and update all imports (e.g., in migration.ts and any other
modules) to consume it from the new location so migration.ts becomes a consumer,
not the source; ensure exported name stays compareSemverStrings and run/adjust
any unit tests or type exports that referenced the old path.
- Around line 261-264: The version-mismatch message that uses minVersion and
currentVersion should be updated to include an actionable upgrade hint; in the
return statement that builds the string using minVersion and currentVersion
(where the code currently returns `ralph-tui requires Bun >= ${minVersion}...
Bun ${currentVersion}`), append a suggestion to run `bun upgrade` and include
the upgrade guide URL (`https://bun.com/docs/guides/util/upgrade`) alongside or
instead of the installation docs so users have an immediate remediation path.
- Extract compareSemverStrings into src/utils/semver.ts so migration.ts is a consumer, not the source; move its tests to semver.test.ts - Read MIN_BUN_VERSION from package.json engines.bun at runtime instead of hardcoding, making package.json the single source of truth - Update error message with 'bun upgrade' hint for immediate remediation - Add test for pre-release version below minimum (1.3.5-beta < 1.3.6) https://claude.ai/code/session_01RuyCDncNpp7xJoDRLoq8Vt
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/cli.tsx (1)
159-160: The dynamicpackage.jsonimport insidehandleSubcommandis now redundant and shadows the module-levelpkg.The static import added at line 27 (
import pkg from '../package.json') already provides the JSON object aspkg. The localconst pkg = await import(…)re-imports the same file, shadows the outerpkgwith a module-namespace object (requiring.default.versioninstead of.version), and adds an unnecessaryasyncdependency to theversionbranch.♻️ Suggested simplification
- // Dynamic import to get version from package.json - const pkg = await import('../package.json', { with: { type: 'json' } }); - console.log(`ralph-tui ${pkg.default.version}`); + console.log(`ralph-tui ${pkg.version}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/cli.tsx` around lines 159 - 160, In handleSubcommand, remove the local dynamic import that shadows the module-level pkg; eliminate "const pkg = await import(...)" and use the already-imported top-level pkg (import pkg from '../package.json') so console.log uses pkg.version instead of pkg.default.version, avoiding the unnecessary await/async dependency and shadowing; update the console.log call in handleSubcommand accordingly.src/utils/semver.ts (1)
15-21:v-prefixed strings silently compare as0.x.y.
parseInt("v1", 10)returnsNaN, which|| 0converts to0, so"v1.3.6"is treated as"0.3.6". Current callers (Bun.version, config version strings) never produce avprefix, so this is benign today, but as the utility gains callers it could bite. A one-liner guard would future-proof it:♻️ Optional robustness fix
export function compareSemverStrings(a: string, b: string): -1 | 0 | 1 { - // Strip any pre-release/build metadata (e.g., "2.0-beta" -> "2.0") - const cleanA = a.split(/[-+]/)[0]; - const cleanB = b.split(/[-+]/)[0]; + // Strip leading 'v' and any pre-release/build metadata (e.g., "v2.0-beta" -> "2.0") + const cleanA = a.replace(/^v/i, '').split(/[-+]/)[0]; + const cleanB = b.replace(/^v/i, '').split(/[-+]/)[0];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/semver.ts` around lines 15 - 21, compareSemverStrings silently treats "v"-prefixed versions as 0.x.y because parseInt returns NaN; fix by normalizing inputs to strip a leading "v" (case-insensitive) before removing pre-release/build metadata so "v1.3.6" becomes "1.3.6"; update the cleanA/cleanB logic in compareSemverStrings (e.g., apply .replace(/^v/i, '') before .split(/[-+]/)[0]) so parsing to integers works correctly for v-prefixed strings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/cli.tsx`:
- Around line 159-160: In handleSubcommand, remove the local dynamic import that
shadows the module-level pkg; eliminate "const pkg = await import(...)" and use
the already-imported top-level pkg (import pkg from '../package.json') so
console.log uses pkg.version instead of pkg.default.version, avoiding the
unnecessary await/async dependency and shadowing; update the console.log call in
handleSubcommand accordingly.
In `@src/utils/semver.ts`:
- Around line 15-21: compareSemverStrings silently treats "v"-prefixed versions
as 0.x.y because parseInt returns NaN; fix by normalizing inputs to strip a
leading "v" (case-insensitive) before removing pre-release/build metadata so
"v1.3.6" becomes "1.3.6"; update the cleanA/cleanB logic in compareSemverStrings
(e.g., apply .replace(/^v/i, '') before .split(/[-+]/)[0]) so parsing to
integers works correctly for v-prefixed strings.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/cli.tsxsrc/setup/migration.test.tssrc/setup/migration.tssrc/utils/semver.test.tssrc/utils/semver.tssrc/utils/validation.test.tssrc/utils/validation.ts
💤 Files with no reviewable changes (1)
- src/setup/migration.test.ts
- Use top-level pkg import for version command instead of redundant
dynamic import that shadowed the module-level binding
- Strip leading "v" prefix in compareSemverStrings so "v1.3.6" parses
correctly instead of silently becoming 0.3.6 via parseInt("v1") → NaN
https://claude.ai/code/session_01RuyCDncNpp7xJoDRLoq8Vt
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/utils/semver.test.ts (1)
39-43: Consider documenting the intentional SemVer spec deviation in the pre-release test.Per the SemVer spec, a pre-release tag makes a version lower than the corresponding release (
2.0-alpha < 2.0), socompareSemverStrings('2.0-alpha', '2.0')returning0rather than-1is a deliberate non-spec behaviour. The test name describes the mechanism ("strips … metadata") but not the semantic consequence, which can mislead future maintainers into assuming full spec compliance.A short comment and/or an extra assertion makes the intent explicit:
✏️ Suggested annotation
test('strips pre-release and build metadata', () => { + // NOTE: Intentionally deviates from SemVer §9 — pre-release tags are + // stripped rather than being given lower precedence than the release. + // This means '2.0-alpha' is treated as equal to '2.0', not less-than. expect(compareSemverStrings('2.0-beta', '2.0')).toBe(0); expect(compareSemverStrings('2.0+build123', '2.0')).toBe(0); expect(compareSemverStrings('2.0-alpha', '2.0-beta')).toBe(0); + // Consequence for the Bun version check: '1.3.6-rc1' is treated as '1.3.6' and passes. + expect(compareSemverStrings('1.3.6-rc1', '1.3.6')).toBe(0); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/semver.test.ts` around lines 39 - 43, The test in semver.test.ts uses compareSemverStrings and currently asserts that pre-release/build metadata are stripped (e.g., compareSemverStrings('2.0-alpha','2.0') === 0) but doesn't document that this deliberately deviates from SemVer (where '2.0-alpha' < '2.0'); update the test by adding a short inline comment next to the compareSemverStrings calls explaining the intentional non‑spec behavior, and optionally add an extra assertion or note that the SemVer spec would expect -1 for '2.0-alpha' vs '2.0' to make the semantic consequence explicit for future maintainers while keeping the existing assertions intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/utils/semver.test.ts`:
- Around line 39-43: The test in semver.test.ts uses compareSemverStrings and
currently asserts that pre-release/build metadata are stripped (e.g.,
compareSemverStrings('2.0-alpha','2.0') === 0) but doesn't document that this
deliberately deviates from SemVer (where '2.0-alpha' < '2.0'); update the test
by adding a short inline comment next to the compareSemverStrings calls
explaining the intentional non‑spec behavior, and optionally add an extra
assertion or note that the SemVer spec would expect -1 for '2.0-alpha' vs '2.0'
to make the semantic consequence explicit for future maintainers while keeping
the existing assertions intact.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/cli.tsxsrc/utils/semver.test.tssrc/utils/semver.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/utils/semver.ts
- src/cli.tsx
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #334 +/- ##
==========================================
- Coverage 45.97% 45.96% -0.01%
==========================================
Files 100 101 +1
Lines 32263 32273 +10
==========================================
+ Hits 14833 14835 +2
- Misses 17430 17438 +8
🚀 New features to boost your workflow:
|
Summary
This PR adds runtime validation to ensure ralph-tui is executed with Bun version 1.3.6 or higher. The application will now fail fast with a clear error message if run on an older Bun version, preventing cryptic runtime errors.
Key Changes
checkBunVersion()function insrc/utils/validation.tsthat compares the current Bun version against a minimum required version using semantic versioning comparisonsrc/cli.tsx) to validate Bun version before any other initialization, with graceful error messaging and exitenginesfieldsrc/utils/validation.test.ts) with 10 test cases covering:Implementation Details
compareSemverStrings()utility from the migration module for consistent semantic version comparison1.3.6-beta) and build metadata (e.g.,1.3.6+build123) are properly handled by stripping them before comparisonhttps://claude.ai/code/session_01RuyCDncNpp7xJoDRLoq8Vt
Summary by CodeRabbit
New Features
Chores
Tests
Refactor