Skip to content

Feature/notifier-update#13

Merged
hectorvent merged 10 commits into
floci-io:mainfrom
juandiii:feature/notifier-update
Jul 11, 2026
Merged

Feature/notifier-update#13
hectorvent merged 10 commits into
floci-io:mainfrom
juandiii:feature/notifier-update

Conversation

@juandiii

@juandiii juandiii commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@greptile-apps

greptile-apps Bot commented Jul 3, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds an npm/gh-style update notifier to the CLI and fixes several correctness issues in UpdateCommand. All four bugs flagged in the previous review round (isExplicitProduct routing, silent downgrade on pre-release builds, missing Version.isValid() guard in UpdateCommand.fetchLatestVersion, and the ambiguous empty-body error message) are addressed here.

  • New UpdateNotifier reads a local cache (~/.floci/update-check.json) to show a hint before the command output, and refreshes that cache on a background virtual thread at most once every 24 h; the check is automatically skipped in CI, piped output, and when FLOCI_NO_UPDATE_CHECK=1 is set.
  • New Version helper provides a minimal semver comparator that guards against captive-portal HTML poisoning the cache and correctly treats a stable release as newer than an equal-cored pre-release.
  • FlociCli routing fix: \"update\" is added to isExplicitProduct so floci update is never prefixed with a product namespace, and isUpdateCommand suppresses the update hint when the user is already running the update command.

Confidence Score: 5/5

Safe to merge after removing the duplicate README table row — the update-notifier path is entirely fail-silent, the routing fix is correct, and all previously flagged bugs are addressed.

All four issues raised in the previous review are fixed. The new UpdateNotifier is fail-silent with proper CI and terminal guards. Version.isNewer correctly handles pre-release ordering. The only finding in this round is a duplicate row in the README table, which does not affect runtime behaviour.

README.md has a duplicate floci update row in the command table that should be removed before merging.

Important Files Changed

Filename Overview
README.md Adds a new floci update section with correct usage examples; introduces a duplicate row in the commands table that should be removed.
src/main/java/io/floci/cli/FlociCli.java Adds update-notification logic and fixes the routing guard — "update" is now included in isExplicitProduct so the product prefix is not prepended, and isUpdateCommand correctly suppresses the hint when the user is already running floci update.
src/main/java/io/floci/cli/commands/UpdateCommand.java Three correctness fixes applied: semantic version comparison for unpinned updates, Version.isValid() guard on the fetched tag, and clearer error message distinguishing 200-with-empty-body from HTTP errors.
src/main/java/io/floci/cli/update/UpdateNotifier.java New class implementing npm/gh-style update hints: cache-read for the notice, background virtual-thread refresh at most every 24h, CI/terminal detection, and captive-portal guard. Implementation is robust and fail-silent.
src/main/java/io/floci/cli/update/Version.java New minimal semver helper: validates version shape, compares numeric cores, and correctly treats a stable release as newer than an equal-cored pre-release.
src/main/java/io/floci/cli/update/UpdateCache.java Simple record holding the persisted cache shape; straightforward and correct.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant FlociCli
    participant UpdateNotifier
    participant CacheFile as ~/.floci/update-check.json
    participant GitHub as GitHub API

    User->>FlociCli: "floci <command>"
    FlociCli->>FlociCli: interactiveRunEnabled()?
    alt "interactive & not update command"
        FlociCli->>UpdateNotifier: pendingNotice(currentVersion)
        UpdateNotifier->>CacheFile: read latestVersion
        CacheFile-->>UpdateNotifier: cached version (or empty)
        UpdateNotifier->>UpdateNotifier: Version.isNewer(cached, current)?
        UpdateNotifier-->>FlociCli: Optional[newer version]
        FlociCli->>User: stderr hint (if newer found)
        FlociCli->>UpdateNotifier: refreshInBackground()
        UpdateNotifier->>CacheFile: "isStale? (>24h)"
        alt cache stale or absent
            UpdateNotifier->>GitHub: GET /releases/latest (virtual thread)
            GitHub-->>UpdateNotifier: tag_name
            UpdateNotifier->>UpdateNotifier: Version.isValid(tag)?
            UpdateNotifier->>CacheFile: write UpdateCache(epoch, version)
        end
    end
    FlociCli->>FlociCli: execute(effectiveArgs)
    FlociCli->>UpdateNotifier: awaitRefresh(250ms)
    FlociCli->>User: System.exit(exitCode)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant FlociCli
    participant UpdateNotifier
    participant CacheFile as ~/.floci/update-check.json
    participant GitHub as GitHub API

    User->>FlociCli: "floci <command>"
    FlociCli->>FlociCli: interactiveRunEnabled()?
    alt "interactive & not update command"
        FlociCli->>UpdateNotifier: pendingNotice(currentVersion)
        UpdateNotifier->>CacheFile: read latestVersion
        CacheFile-->>UpdateNotifier: cached version (or empty)
        UpdateNotifier->>UpdateNotifier: Version.isNewer(cached, current)?
        UpdateNotifier-->>FlociCli: Optional[newer version]
        FlociCli->>User: stderr hint (if newer found)
        FlociCli->>UpdateNotifier: refreshInBackground()
        UpdateNotifier->>CacheFile: "isStale? (>24h)"
        alt cache stale or absent
            UpdateNotifier->>GitHub: GET /releases/latest (virtual thread)
            GitHub-->>UpdateNotifier: tag_name
            UpdateNotifier->>UpdateNotifier: Version.isValid(tag)?
            UpdateNotifier->>CacheFile: write UpdateCache(epoch, version)
        end
    end
    FlociCli->>FlociCli: execute(effectiveArgs)
    FlociCli->>UpdateNotifier: awaitRefresh(250ms)
    FlociCli->>User: System.exit(exitCode)
Loading

Reviews (4): Last reviewed commit: "fix(cli): exempt update from default-pro..." | Re-trigger Greptile

Comment thread src/main/java/io/floci/cli/commands/UpdateCommand.java Outdated
Comment thread src/main/java/io/floci/cli/commands/UpdateCommand.java
Comment thread src/main/java/io/floci/cli/commands/UpdateCommand.java Outdated
@hectorvent

Copy link
Copy Markdown
Contributor

Hi @juandiii,

Thank you for the PR. Please resolve conflicts when you have a chance.

Comment thread src/main/java/io/floci/cli/FlociCli.java
@hectorvent
hectorvent merged commit 2498ea0 into floci-io:main Jul 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants