Skip to content

feat(version): add CLI version check on extension startup#9

Merged
AnnatarHe merged 1 commit intomainfrom
feat/cli-version-check
Jan 8, 2026
Merged

feat(version): add CLI version check on extension startup#9
AnnatarHe merged 1 commit intomainfrom
feat/cli-version-check

Conversation

@AnnatarHe
Copy link
Copy Markdown
Collaborator

Summary

  • Add CLI version check when extension starts
  • Call server API to check if current daemon version is latest
  • Show warning notification if update available with update command
  • Read apiEndpoint and webEndpoint from config file

Test plan

  • Configure apiEndpoint and webEndpoint in ~/.shelltime/config.toml
  • Start JetBrains IDE with daemon running
  • Verify version check API is called
  • Test with outdated version to see warning notification
  • Test "Copy Update Command" action in notification

🤖 Generated with Claude Code

Check daemon CLI version against server API when extension starts.
If a newer version is available, show warning notification with
update command: curl -sSL {webEndpoint}/i | bash

- Add VersionChecker class with HTTP client and notifications
- Read apiEndpoint and webEndpoint from config file
- Show warning only once per session
- Add "Copy Update Command" action to notification

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @AnnatarHe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new feature that automatically checks the installed ShellTime CLI daemon's version when the JetBrains extension starts. It proactively informs users if their CLI is outdated and provides an easy way to update it, enhancing the user experience by ensuring compatibility and access to the latest features. The implementation also allows for custom API and web endpoints to be specified in the configuration.

Highlights

  • CLI Version Check: The extension now performs a version check for the ShellTime CLI daemon upon startup to ensure users are running the latest version.
  • Update Notification: If an outdated CLI version is detected, a warning notification is displayed, offering a convenient 'Copy Update Command' action to facilitate the upgrade process.
  • Configurable Endpoints: The API and web endpoints used for the version check and update command are now configurable via the ~/.shelltime/config.toml file, providing flexibility for different environments.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a CLI version check on extension startup, which is a great enhancement for keeping users on the latest version. The implementation is mostly solid, using coroutines for background work and showing a non-intrusive notification.

My review includes a few suggestions:

  • A fix for a race condition in the version check logic to prevent multiple notifications from appearing when multiple projects are open.
  • A recommendation to use the IDE's CopyPasteManager for better integration when copying text to the clipboard.
  • A suggestion to improve error handling by logging exceptions instead of silently ignoring them, which will help with future debugging.
  • A point about a potentially unused and inefficient function in the config loader.

Overall, these are good changes that improve the user experience.

Comment on lines +28 to +29
@Volatile
private var hasShownWarning = false
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The comment "Version warning already shown this session" implies this flag should be shared across all VersionChecker instances to prevent multiple notifications when multiple projects are open. Currently, it's an instance variable.

Furthermore, the current implementation has a race condition. If checkVersion is called concurrently (e.g., from multiple projects opening), multiple threads could pass the if (hasShownWarning) check before one of them sets it to true, leading to multiple notifications. @Volatile ensures visibility but not atomicity for the check-then-set operation.

To fix both issues, you can move hasShownWarning to a companion object and use java.util.concurrent.atomic.AtomicBoolean to ensure atomicity.

  1. Change the declaration to be in a companion object:
    companion object {
        private val hasShownWarning = java.util.concurrent.atomic.AtomicBoolean(false)
    }
  2. Update the check in checkVersion:
    if (hasShownWarning.get()) { ... }
  3. Update the set operation inside the coroutine to be atomic:
    if (result != null && !result.isLatest) {
        if (hasShownWarning.compareAndSet(false, true)) {
            withContext(Dispatchers.Main) {
                showUpdateWarning(currentVersion, result.latestVersion, project)
            }
        }
    }

Comment on lines +177 to +180
fun getFileConfig(): ShellTimeFileConfig? {
val configFile = findConfigFile() ?: return null
return loadConfigFile(configFile)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This new function getFileConfig appears to be unused within the scope of this pull request. Furthermore, it bypasses the caching mechanism implemented in getConfig(), leading to inefficient file I/O and parsing on every call. The properties it seems intended to expose (apiEndpoint and webEndpoint) are already merged into ShellTimeConfig and available via the cached getConfig() method. If this function is not needed, it should be removed. If it is needed for some other purpose, it should be refactored to leverage the existing caching logic.

Comment on lines +106 to +108
} catch (e: Exception) {
// Silently ignore - version check is optional
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While the version check is an optional feature, completely swallowing exceptions without any logging can make it very difficult to diagnose potential issues. For example, problems with socketClient.getStatus() would go unnoticed. It's better to log the exception, at least at a debug level, to aid in future debugging. You can use the Logger utility class from xyz.shelltime.jetbrains.utils.Logger for this.

Comment on lines +98 to +99
val clipboard = java.awt.Toolkit.getDefaultToolkit().systemClipboard
clipboard.setContents(java.awt.datatransfer.StringSelection(updateCommand), null)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's better to use the IntelliJ Platform's CopyPasteManager for clipboard operations. It's more integrated with the IDE's clipboard handling and is the recommended approach for plugins.

You'll need to add this import:
import com.intellij.openapi.ide.CopyPasteManager

Suggested change
val clipboard = java.awt.Toolkit.getDefaultToolkit().systemClipboard
clipboard.setContents(java.awt.datatransfer.StringSelection(updateCommand), null)
com.intellij.openapi.ide.CopyPasteManager.getInstance().setContents(java.awt.datatransfer.StringSelection(updateCommand))

@claude
Copy link
Copy Markdown

claude Bot commented Jan 7, 2026

Code Review: CLI Version Check Feature

Thank you for this implementation! The feature adds valuable functionality to notify users about available CLI updates. Below is my detailed review:

✅ Strengths

  1. Clean Architecture: The VersionChecker class is well-separated with clear responsibilities
  2. Non-blocking Design: Version check runs asynchronously without impacting IDE startup
  3. User Experience: The notification with "Copy Update Command" action is user-friendly
  4. Proper Resource Management: Includes dispose() methods and proper coroutine cleanup
  5. Follows Conventions: Commit message follows Conventional Commits format with proper scope

🐛 Potential Bugs & Issues

1. Critical: Config Merging Issue in ShellTimeService.updateSettings()

Location: ShellTimeService.kt:74-80

The updateSettings() method does not preserve apiEndpoint and webEndpoint. If a user changes IDE settings after startup, the version checker will lose the endpoint configuration.

Fix: Add these fields when creating the new ShellTimeConfig:

  • apiEndpoint = currentSettings.apiEndpoint
  • webEndpoint = currentSettings.webEndpoint

2. Similar Issue in ShellTimeService.reloadConfig()

Location: ShellTimeService.kt:92-98

Same problem - the method does not copy over the new apiEndpoint and webEndpoint from the reloaded config. Config reload will not pick up changes to API/web endpoints.

Fix: Add apiEndpoint and webEndpoint from fileConfig when creating the new ShellTimeConfig.

3. Race Condition: Version Check Before Daemon Ready

Location: ShellTimeProjectService.kt:76-81

The version check is launched immediately after sender.start(), but there is no guarantee the daemon connection is established. Consider adding a small delay or checking connection status before attempting version check, or make the version check more resilient to early failures.

4. Unused Method: ConfigLoader.getFileConfig()

Location: ConfigLoader.kt:177-180

This new method is added but never used. The version checker reads endpoints from ShellTimeConfig, not directly from file config. Either use this method or remove it. If keeping it, add a KDoc explaining its intended use case.


🔒 Security Considerations

1. URL Injection Risk (Low Severity)

Location: VersionChecker.kt:58

The version parameter is URL-encoded, but the base URL comes from user configuration without validation. Consider adding URL validation to ensure apiEndpoint is a valid HTTP/HTTPS URL.

2. Command Injection in Update Command

Location: VersionChecker.kt:84

The update command includes an arbitrary URL from configuration. If webEndpoint contains shell metacharacters, it could be exploited. Consider validating the webEndpoint format or escaping shell characters. While this is somewhat mitigated by the fact users must manually run the command, it is still worth documenting that users should verify the command before execution.


⚡ Performance Considerations

Network Call Handling: The notification is shown on the Main dispatcher correctly

HTTP Timeout: 5-second timeout is reasonable for a version check

Single Check Per Session: The hasShownWarning flag prevents repeated checks, which is excellent for performance and UX


🧪 Test Coverage

Major Gap: No tests for the new VersionChecker class.

Recommended Tests:

  1. VersionChecker Tests:

    • Test successful version check with isLatest=true
    • Test update available with isLatest=false
    • Test HTTP error handling
    • Test timeout behavior
    • Test that warning is only shown once per session
    • Test proper resource cleanup on dispose
  2. ConfigLoader Tests:

    • Test that apiEndpoint and webEndpoint are loaded from TOML
    • Test that apiEndpoint and webEndpoint are loaded from YAML
    • Test getFileConfig() method if keeping it
  3. Integration Tests:

    • Test that version check is triggered on project startup
    • Test graceful handling when endpoints are not configured

📝 Minor Code Quality Suggestions

  1. Add KDoc to VersionChecker.kt: The class has a comment but could benefit from @param documentation

  2. Constants Naming: VERSION_CHECK_ENDPOINT and VERSION_CHECK_TIMEOUT_MS are well-named ✅

  3. Error Handling: ShellTimeProjectService.kt:106-108 silently ignores all exceptions. Consider at least debug logging

  4. Nullable Project Parameter: showUpdateWarning(..., project: Project?) accepts nullable project. Consider what happens if project is null when calling .notify(project)


📋 Summary

Must Fix Before Merge:

  1. ✋ Fix apiEndpoint/webEndpoint not being preserved in ShellTimeService.updateSettings()
  2. ✋ Fix apiEndpoint/webEndpoint not being used in ShellTimeService.reloadConfig()

Should Address:
3. 🔧 Add tests for VersionChecker functionality
4. 🔧 Remove unused getFileConfig() or document its purpose
5. 🔧 Add URL validation for endpoints

Nice to Have:
6. 💡 Add debug logging for version check failures
7. 💡 Consider small delay before version check to ensure daemon connection
8. 💡 Add KDoc to VersionChecker constructor parameters


Test Plan Verification

The PR test plan looks good, but I would add:

  • Test that version check still works after changing IDE settings
  • Test that version check picks up endpoint changes after config reload
  • Test behavior when daemon is not running at startup

Overall, this is a solid feature implementation with good architecture. The main issues are the config merging bugs that could cause the feature to break after settings changes. Once those are fixed and tests are added, this will be ready to merge! 🚀

@AnnatarHe AnnatarHe merged commit f8391cd into main Jan 8, 2026
6 of 7 checks passed
@AnnatarHe AnnatarHe deleted the feat/cli-version-check branch January 8, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant