Skip to content

Conversation

@kj55-dev
Copy link

@kj55-dev kj55-dev commented Jan 10, 2026

Summary

  • Fixes the issue where --version shows stale/incorrect version after updates
  • Adds channel-aware version checking (beta users get beta OR stable, whichever is newer)
  • Properly compares versions using semver instead of string equality

Problem

The CLI was bundling package.json at build time, causing the version to be frozen to whatever was in the source when built - not the actual installed version. This led to:

  • oh-my-opencode --version showing 2.14.0 even when 3.0.0-beta.2 was installed
  • Beta users not being notified of newer stable releases
  • String comparison (!==) instead of semver causing incorrect update suggestions

Solution

Created a new src/shared/version/ module with:

File Purpose
semver.ts Zero-dependency semver parsing & comparison
channels.ts Release channel detection (stable/beta/alpha/rc)
registry.ts NPM registry integration (fetches all dist-tags)
resolver.ts Runtime version resolution
index.ts Main checkVersion() API

Key Changes

  1. Runtime version resolution - Version is now read from package.json at runtime by walking up from the executing file, not bundled at build time

  2. Channel-aware updates:

    • Stable users: only see stable updates
    • Beta users: see whichever is newer (beta OR stable)
    • e.g., if on 3.0.0-beta.2 and 3.0.0 stable releases, user is offered stable
  3. Proper semver comparison - Uses actual semver logic instead of string equality

Testing

$ oh-my-opencode --version
3.0.0-beta.2  # Now shows correct version

$ oh-my-opencode get-local-version
oh-my-opencode Version Information
──────────────────────────────────────────────────

  Current Version: 3.0.0-beta.2 (Beta)
  Latest (beta):  3.0.0-beta.2
  Other Channels:  beta@3.0.0-beta.2

  ✓ You're up to date!

Files Changed

  • src/shared/version/ - New version management module (6 files)
  • src/cli/index.ts - Use runtime version
  • src/cli/get-local-version/ - Use new version utilities, show channel info
  • src/hooks/auto-update-checker/index.ts - Channel-aware update checking

Summary by cubic

Fixes stale --version by resolving the version at runtime and adds channel-aware updates using proper semver. CLI and auto-update now respect and display release channels so users get the right updates.

  • New Features

    • New shared version module: zero-dep semver, channel detection, NPM dist-tags, and runtime version resolver.
    • Channel-aware updates: stable sees stable; prerelease users get the newer of their channel or stable.
    • get-local-version shows channel, latest for channel, other available channels, and channel-specific update hints.
    • Auto-update checker uses the new logic and includes channel info in notifications.
  • Bug Fixes

    • --version now reflects the installed version (no more build-time freeze).
    • Update checks use semver instead of string comparison, preventing incorrect prompts.
    • Pinned exact versions are not auto-updated; pinned dist-tags are updated safely.

Written for commit fc554c5. Summary will update on new commits.

- Add new src/shared/version/ module with:
  - Zero-dependency semver parsing and comparison
  - Release channel detection (stable/beta/alpha/rc)
  - NPM registry integration (fetches all dist-tags)
  - Runtime version resolution (avoids build-time bundling)

- Fix CLI to use runtime version resolution instead of bundled package.json
  - Resolves issue where --version showed stale version after updates

- Update auto-update checker to be channel-aware:
  - Beta users now get whichever is newer (beta OR stable)
  - Stable users only see stable updates
  - Proper semver comparison instead of string equality

- Update get-local-version command to show channel info
@github-actions
Copy link
Contributor

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA).

To sign the CLA, please comment on this PR with:

I have read the CLA Document and I hereby sign the CLA

This is a one-time requirement. Once signed, all your future contributions will be automatically accepted.


I have read the CLA Document and I hereby sign the CLA


dev seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@kj55-dev
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 11 files

Confidence score: 3/5

  • Local dev detection no longer works because src/hooks/auto-update-checker/index.ts never flags file/local entries, so auto-updates would continue running even when someone is hacking locally—real user impact if merged.
  • src/shared/version/semver.ts uses parseInt on prerelease identifiers, so mixed alphanumeric tags like 1abc are mis-sorted and could trigger incorrect upgrade/downgrade decisions.
  • The same semver module also accepts invalid prerelease/build strings (e.g., empty identifiers), meaning bad version strings are treated as valid and could propagate through version checks.
  • Pay close attention to src/hooks/auto-update-checker/index.ts, src/cli/get-local-version/index.ts, src/shared/version/semver.ts - regressions in local dev detection and semver validation need fixes before merge.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/shared/version/semver.ts">

<violation number="1" location="src/shared/version/semver.ts:7">
P2: Permissive semver regex accepts invalid prerelease/build with empty identifiers (e.g., trailing or double dots), causing parse() to treat invalid versions as valid</violation>

<violation number="2" location="src/shared/version/semver.ts:60">
P2: Using `parseInt` incorrectly identifies mixed alphanumeric prerelease identifiers as numeric. For example, `parseInt('1abc', 10)` returns `1` (not NaN), so `'1.0.0-1abc'` would be incorrectly compared against `'1.0.0-2'`. Per semver spec, only identifiers consisting entirely of digits should be compared numerically. Use a regex test like `/^\d+$/` to check for pure numeric identifiers first.</violation>
</file>

<file name="src/cli/get-local-version/index.ts">

<violation number="1" location="src/cli/get-local-version/index.ts:14">
P2: Local dev detection regressed: findPluginEntry never returns file:// entries, so the new file:// check always fails and local dev configs are misclassified as non-local.</violation>
</file>

<file name="src/hooks/auto-update-checker/index.ts">

<violation number="1" location="src/hooks/auto-update-checker/index.ts:69">
P1: Local dev mode detection is broken—`findPluginEntry` never returns file/local entries, so `isLocalDev` is always false and auto-updates run during local development</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


// Check for local dev mode
const pluginInfo = findPluginEntry(ctx.directory)
const isLocalDev = pluginInfo?.entry.startsWith("file://") ?? false
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 10, 2026

Choose a reason for hiding this comment

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

P1: Local dev mode detection is broken—findPluginEntry never returns file/local entries, so isLocalDev is always false and auto-updates run during local development

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/auto-update-checker/index.ts, line 69:

<comment>Local dev mode detection is broken—`findPluginEntry` never returns file/local entries, so `isLocalDev` is always false and auto-updates run during local development</comment>

<file context>
@@ -50,13 +58,17 @@ export function createAutoUpdateCheckerHook(ctx: PluginInput, options: AutoUpdat
+
+        // Check for local dev mode
+        const pluginInfo = findPluginEntry(ctx.directory)
+        const isLocalDev = pluginInfo?.entry.startsWith("file://") ?? false
+
+        if (isLocalDev) {
</file context>
Fix with Cubic

Comment on lines +60 to +75
const aNum = parseInt(ai, 10)
const bNum = parseInt(bi, 10)

if (!isNaN(aNum) && !isNaN(bNum)) {
if (aNum > bNum) return 1
if (aNum < bNum) return -1
} else if (!isNaN(aNum)) {
// Numeric < alphanumeric
return -1
} else if (!isNaN(bNum)) {
return 1
} else {
// Both alphanumeric, compare as strings
if (ai > bi) return 1
if (ai < bi) return -1
}
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 10, 2026

Choose a reason for hiding this comment

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

P2: Using parseInt incorrectly identifies mixed alphanumeric prerelease identifiers as numeric. For example, parseInt('1abc', 10) returns 1 (not NaN), so '1.0.0-1abc' would be incorrectly compared against '1.0.0-2'. Per semver spec, only identifiers consisting entirely of digits should be compared numerically. Use a regex test like /^\d+$/ to check for pure numeric identifiers first.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/shared/version/semver.ts, line 60:

<comment>Using `parseInt` incorrectly identifies mixed alphanumeric prerelease identifiers as numeric. For example, `parseInt('1abc', 10)` returns `1` (not NaN), so `'1.0.0-1abc'` would be incorrectly compared against `'1.0.0-2'`. Per semver spec, only identifiers consisting entirely of digits should be compared numerically. Use a regex test like `/^\d+$/` to check for pure numeric identifiers first.</comment>

<file context>
@@ -0,0 +1,188 @@
+    if (bi === undefined) return 1
+
+    // Numeric identifiers compared as integers
+    const aNum = parseInt(ai, 10)
+    const bNum = parseInt(bi, 10)
+
</file context>
Suggested change
const aNum = parseInt(ai, 10)
const bNum = parseInt(bi, 10)
if (!isNaN(aNum) && !isNaN(bNum)) {
if (aNum > bNum) return 1
if (aNum < bNum) return -1
} else if (!isNaN(aNum)) {
// Numeric < alphanumeric
return -1
} else if (!isNaN(bNum)) {
return 1
} else {
// Both alphanumeric, compare as strings
if (ai > bi) return 1
if (ai < bi) return -1
}
const aIsNumeric = /^\d+$/.test(ai)
const bIsNumeric = /^\d+$/.test(bi)
if (aIsNumeric && bIsNumeric) {
const aNum = parseInt(ai, 10)
const bNum = parseInt(bi, 10)
if (aNum > bNum) return 1
if (aNum < bNum) return -1
} else if (aIsNumeric) {
// Numeric < alphanumeric
return -1
} else if (bIsNumeric) {
return 1
} else {
// Both alphanumeric, compare as strings
if (ai > bi) return 1
if (ai < bi) return -1
}
Fix with Cubic

const pluginInfo = findPluginEntry(directory)

// Check for local dev mode (file:// protocol)
const isLocalDev = pluginInfo?.entry.startsWith("file://") ?? false
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 10, 2026

Choose a reason for hiding this comment

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

P2: Local dev detection regressed: findPluginEntry never returns file:// entries, so the new file:// check always fails and local dev configs are misclassified as non-local.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/cli/get-local-version/index.ts, line 14:

<comment>Local dev detection regressed: findPluginEntry never returns file:// entries, so the new file:// check always fails and local dev configs are misclassified as non-local.</comment>

<file context>
@@ -1,29 +1,39 @@
+    const pluginInfo = findPluginEntry(directory)
+    
+    // Check for local dev mode (file:// protocol)
+    const isLocalDev = pluginInfo?.entry.startsWith("file://") ?? false
+
+    if (isLocalDev) {
</file context>
Fix with Cubic


import type { ParsedVersion, VersionDiff } from "./types"

const SEMVER_REGEX = /^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.-]+))?(?:\+([a-zA-Z0-9.-]+))?$/
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 10, 2026

Choose a reason for hiding this comment

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

P2: Permissive semver regex accepts invalid prerelease/build with empty identifiers (e.g., trailing or double dots), causing parse() to treat invalid versions as valid

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/shared/version/semver.ts, line 7:

<comment>Permissive semver regex accepts invalid prerelease/build with empty identifiers (e.g., trailing or double dots), causing parse() to treat invalid versions as valid</comment>

<file context>
@@ -0,0 +1,188 @@
+
+import type { ParsedVersion, VersionDiff } from "./types"
+
+const SEMVER_REGEX = /^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.-]+))?(?:\+([a-zA-Z0-9.-]+))?$/
+
+/**
</file context>
Suggested change
const SEMVER_REGEX = /^v?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.-]+))?(?:\+([a-zA-Z0-9.-]+))?$/
const SEMVER_REGEX = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/
Fix with Cubic

renekris added a commit to renekris/oh-my-glm that referenced this pull request Jan 10, 2026
@kdcokenny
Copy link
Collaborator

recheck

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.

2 participants