feat: add upgrade notification when newer CLI version is available#157
feat: add upgrade notification when newer CLI version is available#157
Conversation
🚀 Package Preview Available!Install this PR's preview build with npm: npm i @base44-preview/cli@0.0.28-pr.157.1c22a99Prefer not to change any import paths? Install using npm alias so your code still imports npm i "base44@npm:@base44-preview/cli@0.0.28-pr.157.1c22a99"Or add it to your {
"dependencies": {
"base44": "npm:@base44-preview/cli@0.0.28-pr.157.1c22a99"
}
}
Preview published to npm registry — try new features instantly! |
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
0465937 to
49a22bb
Compare
src/cli/utils/runCommand.ts
Outdated
| const { outroMessage } = await commandFn(); | ||
| outro(outroMessage || ""); | ||
|
|
||
| // Check for available upgrades (non-blocking) |
There was a problem hiding this comment.
There was a problem hiding this comment.
@claude this whole file should be inside the src/cli folder because it's not related to the core/ of the product
There was a problem hiding this comment.
Claude finished @kfirstri's task in 1m 34s —— View job
Completed
- Read current file structure and imports
- Move src/core/utils/version-check.ts to src/cli/utils/version-check.ts
- Update import path in upgradeNotification.ts
- Move test file to tests/cli/version-check.spec.ts
- Commit and push changes
Moved version-check.ts from src/core/utils to src/cli/utils and updated all related imports. The test file has also been moved from tests/core to tests/cli to match the new structure.
--- | Branch
|
@claude go over the tests, remove tests/core and create correct tests inside the tests/cli folder. |
|
Claude finished @kfirstri's task in 1m 57s —— View job Reorganizing tests to tests/cli folder
Completed WorkI've successfully reorganized the test file:
Unable to PushI cannot push the changes because the remote branch has diverged and I need to sync first. I require approval to run What was done: The test file has been correctly moved to |
| try { | ||
| const upgradeInfo = await checkForUpgrade(); | ||
| if (upgradeInfo) { | ||
| log.message(formatUpgradeMessage(upgradeInfo)); |
There was a problem hiding this comment.
@claude i see were using log.message, and the printUpgradeNotificationIfAvailable is called in runCommand but after we already do outro meaning it will be a weird hevaior, maybe we can do it at the begining?
There was a problem hiding this comment.
Claude finished @kfirstri's task in 47s —— View job
Completed
- Read runCommand.ts to understand current placement
- Read upgradeNotification.ts to understand implementation
- Move notification call to beginning of command
- Commit and push changes
Moved the upgrade notification to display right after the intro/banner, before the main command logic runs. This prevents the notification from appearing after the outro, which would have created strange behavior where messages appear after the command completion message.
The notification now appears at the beginning of the command flow, making it more visible and avoiding any confusion with the outro message.
| Branch
src/cli/utils/version-check.ts
Outdated
| */ | ||
| export async function checkForUpgrade(): Promise<UpgradeInfo | null> { | ||
| try { | ||
| const { stdout } = await execa("npm", ["view", "base44", "version"], { timeout: 5000 }); |
There was a problem hiding this comment.
look for other places we use execa and make sure we pass all appropriate flags @claude
There was a problem hiding this comment.
Claude finished @kfirstri's task in 1m 12s —— View job
Reviewing execa usage patterns 
- Read current version-check.ts to understand current execa usage
- Search for all execa usage in the codebase
- Compare flags and options used across the codebase
- Update version-check.ts to add shell: true flag
- Commit changes locally
- Sync with remote and push changes
Findings
I found that version-check.ts is missing the shell: true flag that is consistently used throughout the codebase:
Previous usage in version-check.ts:14
const { stdout } = await execa("npm", ["view", "base44", "version"], { timeout: 5000 });Updated to match codebase pattern:
const { stdout } = await execa("npm", ["view", "base44", "version"], {
timeout: 5000,
shell: true
});Why this matters: According to AGENTS.md:729-736, the shell: true flag suppresses subprocess output, which is important for UI consistency. All other execa calls in the codebase (create.ts:206, create.ts:209, create.ts:232) use this flag.
Status
The change has been committed locally (commit: fe03574). I need approval to run git pull --rebase to sync with the remote branch before pushing, as the remote has diverged.
| Branch
There was a problem hiding this comment.
Claude finished @gonengar's task in 1m 7s —— View job
Completed
- Check git status and current file state
- Add
shell: trueflag to execa call - Commit the change
- Push to remote
Summary
Added the shell: true flag to the execa call on line 14 of src/cli/utils/version-check.ts. This matches the pattern used consistently throughout the codebase (as seen in create.ts).
According to CLAUDE.md, the shell: true flag suppresses subprocess output, which is important for UI consistency when running background operations.
Changes committed and pushed to branch claude/add-upgrade-notification-IF6u3 (commit: fe39b9d).
| Branch
tests/cli/version-check.spec.ts
Outdated
| @@ -0,0 +1,54 @@ | |||
| import { describe, it, expect, vi, beforeEach } from "vitest"; | |||
| import { execa } from "execa"; | |||
| import { checkForUpgrade } from "@/cli/utils/version-check.js"; | |||
There was a problem hiding this comment.
@claude this should work like other tests in cli/, use the testkit and run the program.. look for other examples and fix
There was a problem hiding this comment.
Claude finished @kfirstri's task in 2m 8s —— View job
Completed
- Read current test file
- Find and analyze other CLI test examples
- Understand testkit pattern
- Rewrite test to use testkit
- Commit and push changes
Changes Made
Rewrote tests/cli/version-check.spec.ts to follow the testkit pattern used by other CLI tests:
Before: Unit tests that mocked execa to test the checkForUpgrade function in isolation
After: Integration tests that:
- Use
setupCLITests()to get the test context - Run actual CLI commands (e.g.,
whoami) usingt.run() - Mock the
checkForUpgradefunction at the module level usingvi.mock() - Verify upgrade notifications appear in the command output
This is a hybrid approach: we use testkit for end-to-end command execution (following the pattern of other CLI tests), but we mock the checkForUpgrade function since it depends on npm subprocess calls that can't be intercepted by the testkit.
The tests now verify the upgrade notification feature by:
- Running a command that should display the notification
- Checking that the output contains "Update available!" and the version info
- Verifying error cases don't block command execution
Changes committed and pushed to the branch. CI will run the tests automatically.
| Branch
4ef86e1 to
4ff5804
Compare
src/cli/utils/version-check.ts
Outdated
|
|
||
| try { | ||
| const { stdout } = await execa("npm", ["view", "base44", "version"], { | ||
| timeout: 5000, |
There was a problem hiding this comment.
@claude lower this timout to 500. also add a CI=1 env var to make sure it doesn't render loaders
There was a problem hiding this comment.
Claude finished @kfirstri's task in 50s —— View job
Completed
- Read current version-check.ts file
- Lower timeout to 500ms
- Add CI=1 environment variable to prevent loader rendering
- Commit and push changes
Summary
Updated src/cli/utils/version-check.ts with the requested changes:
- Reduced timeout: Changed from 5000ms to 500ms for faster failure when npm registry is unavailable
- Added CI environment variable: Added
env: { CI: "1" }to the execa call to suppress npm loaders in CI environments
The CI=1 environment variable is a standard convention that npm (and many other tools) recognize to disable interactive features like progress bars and spinners, which is important for clean CI/CD output.
Changes committed and pushed to branch claude/add-upgrade-notification-IF6u3 (commit: dc0da09).
--- | Branch
There was a problem hiding this comment.
@claude can you push the changes to this branch?
There was a problem hiding this comment.
Claude finished @gonengar's task in 1m 24s —— View job
I've implemented both requested changes:
- version-check.ts:25 - Lowered timeout to 500ms and added CI=1 env var
- config.ts:37 - Moved TestOverrides to schema.ts as a Zod schema
Tasks
- Check git status and current branch state
- Review the specific review comments to understand what changes are needed
- Lower timeout to 500ms in version-check.ts
- Add CI=1 environment variable to version-check.ts
- Move TestOverrides interface to schema.ts as a Zod schema
- Update getTestOverrides() to use .safeParse()
- Commit changes locally
- Push changes to remote branch
Changes Made
src/cli/utils/version-check.ts
- Changed timeout from
5000to500ms - Added
env: { CI: "1" }to suppress npm loaders
src/core/project/schema.ts
- Added
TestOverridesSchemaas a Zod schema - Exported
TestOverridestype inferred from the schema
src/core/config.ts
- Removed
TestOverridesinterface (now in schema.ts) - Updated
getTestOverrides()to useTestOverridesSchema.safeParse()for validation - Added import for the schema
Unable to Push
The changes are committed locally (commit: fd09ffc), but I cannot push them because the remote branch has diverged. I need approval to run git pull --rebase to sync with the remote branch before pushing.
The git commands git pull and git fetch are currently blocked by tool permissions.
--- | Branch
There was a problem hiding this comment.
Claude finished @gonengar's task in 1m 2s —— View job
Completed
- Check git status and recent commits
- Verify version-check.ts changes needed
- Verify TestOverrides is already moved to Zod schema
- Implement timeout and CI env var changes
- Commit and push changes
Summary
Yes, I was able to complete the requested changes! Here's what was done:
Changes Implemented:
- Lowered npm registry timeout from
5000msto500msinsrc/cli/utils/version-check.ts - Added
env: { CI: "1" }to the execa call to suppress npm loaders during version checks
Already Completed:
- TestOverrides moved to Zod schema (already done in commit 2826286)
The changes have been committed and pushed to the branch claude/add-upgrade-notification-IF6u3 (commit: 48411c8).
--- | Branch
src/core/config.ts
Outdated
| export interface TestOverrides { | ||
| appConfig?: { id: string; projectRoot: string }; | ||
| latestVersion?: string | null; | ||
| } |
There was a problem hiding this comment.
@claude move this into the src/core/project/schema.ts and implement as zod schema, and then here in the getTestOverrides, use the zod schema .safeParse
There was a problem hiding this comment.
Claude finished @kfirstri's task in 1m 17s —— View job
Completed
- Read current TestOverrides interface in src/core/config.ts
- Read src/core/project/schema.ts to understand schema patterns
- Create Zod schema for TestOverrides in schema.ts
- Update getTestOverrides() to use .safeParse()
- Commit and push changes
Summary
Moved TestOverrides from a TypeScript interface in config.ts to a Zod schema in schema.ts and updated getTestOverrides() to use .safeParse() for validation.
Changes made:
- Created
TestOverridesSchemainsrc/core/project/schema.tswith proper Zod validation - Removed the TypeScript interface from
config.tsand imported the type fromschema.ts - Updated
getTestOverrides()to useTestOverridesSchema.safeParse()for runtime validation - Returns
nullif validation fails, maintaining the same error handling behavior
The schema now provides runtime validation for test overrides, ensuring type safety at both compile-time and runtime.
Changes committed and pushed to branch claude/add-upgrade-notification-IF6u3 (commit: 62049c4).
--- | Branch
There was a problem hiding this comment.
@claude can you push the change to this branch?
There was a problem hiding this comment.
Claude finished @gonengar's task in 1m 12s —— View job
Completed
- Check git status and recent commits
- Verify TestOverrides change was not yet implemented
- Add TestOverrides Zod schema to src/core/project/schema.ts
- Update getTestOverrides() to use .safeParse()
- Commit and push changes
Summary
I've successfully implemented the requested change to move TestOverrides from a TypeScript interface to a Zod schema:
Changes made:
- Added
TestOverridesSchematosrc/core/project/schema.tswith proper Zod validation - Removed the TypeScript interface from
config.tsand imported the type fromschema.ts - Updated
getTestOverrides()to useTestOverridesSchema.safeParse()for runtime validation - Returns
nullif validation fails, maintaining the same error handling behavior
The schema now provides runtime validation for test overrides, ensuring type safety at both compile-time and runtime.
Changes committed and pushed to branch claude/add-upgrade-notification-IF6u3 (commit: 2826286).
--- | Branch
- Add version check utility that fetches latest version from npm registry - Implement 24-hour cache to avoid frequent npm requests - Display golden-colored notification after command completion - Notification shows current → latest version and install command https://claude.ai/code/session_0154kVA7ZVJqChXFvgWRUfLH
Tests cover: - Returns upgrade info when newer version available - Returns null when version is the same - Returns null when npm command fails - Trims whitespace from version output https://claude.ai/code/session_0154kVA7ZVJqChXFvgWRUfLH
Co-authored-by: Kfir Stri <kfirstri@users.noreply.github.com>
Moved version-check.ts and its test file from core/utils to cli/utils as this functionality is CLI-specific and not related to core product. Co-authored-by: Kfir Stri <kfirstri@users.noreply.github.com>
Moved printUpgradeNotificationIfAvailable call to execute right after intro/banner display, before the main command logic runs. This prevents the notification from appearing after outro, which would create a weird behavior where messages appear after the command completion message. Co-authored-by: Kfir Stri <kfirstri@users.noreply.github.com>
- Use setupCLITests() to run actual CLI commands end-to-end - Mock checkForUpgrade at module level since it depends on npm subprocess - Test upgrade notification by running whoami command and checking output - This follows the same pattern as other CLI tests Co-authored-by: Kfir Stri <kfirstri@users.noreply.github.com>
Co-authored-by: Gonen Jerbi <gonengar@users.noreply.github.com>
- Add latestVersion to BASE44_CLI_TEST_OVERRIDES for test control - Add .not.toContain() support to CLIResultMatcher - Add givenLatestVersion() method to CLITestkit - Rewrite version-check tests to use test overrides instead of vi.mock() The vi.mock() approach doesn't work when testing against bundled dist because path aliases are resolved at build time. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add section explaining how to use and extend BASE44_CLI_TEST_OVERRIDES for testing behaviors that can't be mocked with vi.mock() due to bundling. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Simplify by adding toNotContain() directly to CLIResultMatcher instead of a separate class with .not property. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use toContain(text, false) instead of separate toNotContain method. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move test overrides parsing to src/core/config.ts and use it from both version-check.ts and app-config.ts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
62049c4 to
5baf1da
Compare
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
src/cli/utils/upgradeNotification.ts
Outdated
| return `${shinyOrange("Update available!")} ${shinyOrange(`${info.currentVersion} → ${info.latestVersion}`)} ${shinyOrange("Run:")} ${bold(shinyOrange("npm update -g base44"))}`; | ||
| } | ||
|
|
||
| /** |
There was a problem hiding this comment.
Co-authored-by: Gonen Jerbi <gonengar@users.noreply.github.com>
Move TestOverrides interface from TypeScript to Zod schema and use .safeParse() for runtime validation of test overrides. Co-authored-by: Gonen Jerbi <gonengar@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
Co-authored-by: Gonen Jerbi <gonengar@users.noreply.github.com>
Note
Description
This PR adds automatic upgrade notifications to the Base44 CLI. When users run any command, the CLI checks for newer versions on npm and displays a notification immediately after the banner if an upgrade is available. The implementation includes defensive error handling to ensure version checks never disrupt user workflows, with a 500ms timeout and CI environment variable to prevent interference with npm operations. Additionally, this PR introduces a centralized test override mechanism (
BASE44_CLI_TEST_OVERRIDES) using Zod schemas for type-safe runtime validation, enabling comprehensive testing of behaviors that cannot be mocked withvi.mock()due to the bundled distribution architecture.Related Issue
None
Type of Change
Changes Made
Upgrade Notification Feature:
version-check.tsutility that fetches latest version from npm registry usingexecawith 500ms timeout andCI=1environment variableupgradeNotification.tsthat formats and displays upgrade notifications using theme's shiny orange colorrunCommand.tsto display notifications after banner, before command executionUpdate available! 0.0.26 → 1.0.0 Run: npm update -g base44Test Infrastructure Improvements:
BASE44_CLI_TEST_OVERRIDESenvironment variable for centralized test mocking via JSONTestOverridesSchemainsrc/core/project/schema.tsusing Zod with runtime validation via.safeParse()getTestOverrides()utility insrc/core/config.tsfor shared, type-safe access to test overridesapp-config.tsto use the sharedgetTestOverrides()utility, consolidating test override logicCLITestkitwithgivenLatestVersion()method and improved environment variable snapshot handlingtoNotContain()matcher toCLIResultMatcherfor negative assertions in teststests/cli/version-check.spec.tscovering three scenarios: newer version available, current version (null), and no overrideDocumentation:
AGENTS.mdwith detailed "Test Overrides" section documenting theBASE44_CLI_TEST_OVERRIDESpatternvi.mock()doesn't work with bundled code (path aliases resolved at build time)Testing
npm test)Checklist
Additional Notes
Error Handling Philosophy:
The implementation gracefully handles all failure scenarios. If npm is unavailable, the registry is unreachable, or the command times out (500ms), the notification is silently skipped without any impact on the user experience. This ensures the version check never becomes a point of failure for CLI operations.
Test Override Architecture:
Tests run against bundled
dist/index.jswhere path aliases (@/) are resolved at build time, makingvi.mock("@/some/path.js")ineffective. TheBASE44_CLI_TEST_OVERRIDESpattern provides a runtime override mechanism that works with bundled code and is now documented with Zod schema validation for type safety. This approach is extensible for future testing needs.Performance Considerations:
CI=1environment variable prevents npm from interfering with package operations🤖 Generated by Claude | 2026-02-03 09:30 UTC