Skip to content

refactor(agents): user-friendly agent version handling — warn once, never block - #463

Open
SleepySML wants to merge 13 commits into
codemie-ai:mainfrom
SleepySML:EPMCDME-13734
Open

refactor(agents): user-friendly agent version handling — warn once, never block#463
SleepySML wants to merge 13 commits into
codemie-ai:mainfrom
SleepySML:EPMCDME-13734

Conversation

@SleepySML

Copy link
Copy Markdown
Contributor

Summary

EPMCDME-13734. Replace the blocking agent-version checks with a one-time, non-blocking "untested version" notice per (agent, agent-version, codemie-version) tuple. Every pinned per-agent supported-version constant is removed, so agent CLIs can release independently without a CodeMie release to keep users unblocked.

Users are never prevented from launching a wrapped agent by a version check; they are never nagged more than once about the same tuple; and non-interactive/ACP/silent contexts never throw and never open an inquirer.prompt.

Changes

  • Agent core: new BaseAgentAdapter.warnOnceIfUntested() and getVersionInfo() seams. run()'s old blocking inquirer.prompt / process.exit / throw version-check block is gone. warnOnceIfUntested() is logger.warn + optional chalk.yellow banner to stderr — never blocks, never throws.
  • New state store: ~/.codemie/version-warnings.json via VersionWarningStore (MigrationTracker pattern). Idempotent record/read, graceful degradation on read failures (hasWarned returning false) and write failures (marker re-emits on next launch).
  • Pinned constants removed across the four plugins: CLAUDE_SUPPORTED_VERSION, CLAUDE_MINIMUM_SUPPORTED_VERSION, and the codex / gemini / kimi equivalents — 8 constants total. AgentMetadata.supportedVersion / minimumSupportedVersion and VersionCompatibilityResult deleted.
  • CLI callers rewired: install.ts (--supported is now a silent alias for --latest; post-install warnOnceIfUntested() records the marker), update.ts (queries npm registry directly for Claude; emits warnOnceIfUntested() after every update path), setup.ts (3-second Promise.race wraps both getVersionInfo and warnOnceIfUntested).
  • Doctor: new codemie doctor --reset-version-warnings flag clears the store. AgentsCheck renders three states — Acknowledged (chalk.green), Untested (chalk.yellow), Not installed (chalk.gray). Deprecated-npm-install warning preserved.
  • Test isolation: tests/setup/agent-build-setup.ts no longer imports CLAUDE_SUPPORTED_VERSION — it unconditionally installs claude --latest so integration tests always run against a predictable binary.
  • Tests: 30 new / rewritten test cases (VersionWarningStore, isInteractive, warnOnceIfUntested including the null-codemieVersion early return, AgentsCheck three-state rendering + graceful degradation when hasWarned throws, install.ts no longer reads metadata.supportedVersion, codex plugin one-time-warning contract).

Impact

User-visible behavior change. First launch with an unacknowledged agent version:

$ codemie claude
⚠  CodeMie has not yet been tested with claude v2.1.219 (running CodeMie v0.11.0).
   Proceeding — this notice is shown once.
   If anything looks off, you can install a different version with:
     codemie install claude --latest

<agent starts normally>

Subsequent launches of the same tuple: silent. Non-interactive / ACP / CI: logger.warn only, no stdout prose, never blocks.

Deliberate behavior change to call out: ACP silentMode used to throw on isBelowMinimum (per the prior ADR). It now logs and proceeds. This is the ticket AC's "never throw and never block on version mismatch" contract — callers that treated the throw as an integration signal should switch to reading codemie doctor output or the log file.

codemie install <agent> --supported still works (silent alias for --latest) — no script breakage.

Checklist

  • Self-reviewed (two-round code review via SDLC Factory orchestrator: final request-changes → check approve)
  • Manual testing performed (2660 unit tests + 204 CLI integration tests pass locally)
  • Documentation updated (spec + plan + technical-analysis under docs/superpowers/tasks/2026-08-04-untested-agent-version-warning-non-blocking/)
  • No breaking changes (or clearly documented) — ACP silentMode throwlog-and-proceed is called out above

Local skipped gates (still enforced by CI):

  • license-check — npm cache EACCES in this environment
  • validate:secrets — no local container engine; CI runs gitleaks unconditionally
  • Agent-integration project (vitest run --project agent) — requires live Claude installation + credentials

@@ -285,7 +289,7 @@ export function createUpdateCommand(): Command {
if (!result.hasUpdate) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Both branches of if (agent.name === 'claude') / else now print the exact same string — this used to differ ("latest supported version" for Claude), but the text was dropped when pinned versions were
removed (EPMCDME-13734), leaving the branch and the comment above it stale. Dead code. Can be simplified to:
spinner.succeed(${agent.displayName} is already up to date (${result.currentVersion}));
return;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — collapsed into a single spinner.succeed line in 1581850. The "For Claude, clarify…" comment is gone too since it no longer applies.

Comment thread src/cli/commands/install.ts Outdated
}
// One-time untested-version notice for the freshly-installed CLI.
// No-op if the tuple has already been acknowledged in a prior session.
if (displayVersion && 'warnOnceIfUntested' in agent) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warnOnceIfUntested is now a required (non-optional) method on AgentAdapter, so the 'warnOnceIfUntested' in agent check and the unknown cast here are unnecessary:
if (displayVersion) {
await agent.warnOnceIfUntested();
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — dropped both the 'warnOnceIfUntested' in agent guard and the unknown cast in 1581850. Direct await agent.warnOnceIfUntested() now.

Comment thread src/utils/version-warnings.ts Outdated
await fs.writeFile(file, JSON.stringify(history, null, 2), 'utf-8');
}

static async hasWarned(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The "already warned" key includes the CodeMie version, not just the agent version. Practically: every time CodeMie itself ships a new release, all previously-acknowledged agent versions go back to
"Untested," and the user sees the warning again on their next launch even though the agent itself didn't change. This doesn't block anything, it just means the notice can reappear more often than the
ticket implies ("warn once, then stay silent"). This is a documented, intentional choice in spec.md just want to confirm it's the intended behavior and not an oversight.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed intentional. The compatibility surface is (agent-version × codemie-version), not agent-version alone — CodeMie 0.11 → 0.12 can ship a change in how it wraps the agent (env mapping, hooks, proxy behavior), so an acknowledgement of claude 2.1.218 × codemie 0.11.0 doesn't automatically extend to claude 2.1.218 × codemie 0.12.0. The signal is the mildest possible: one chalk.yellow line to stderr on interactive TTY, logger.warn only in non-interactive contexts, never blocks. Reset is one command: codemie doctor --reset-version-warnings. Documented in spec.md under "State file" / "Warn once per (agent, agentVersion, codemieVersion) tuple" — happy to revisit the key shape (drop codemieVersion, or downgrade to log-only after N consecutive CodeMie releases) if it turns out too noisy in practice; just wanted to lock the strict interpretation of "one-time per tuple" first.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fair point — walking back my previous reply. Went back to the ticket and my "documented intentional design" defense was rationalisation:

  • The ticket AC feat: Add Release Manager agent and CI/CD automation #2 literally says "for a specific agent agent version combination" — 2-tuple language.
  • The Summary says "warns once per agent version" — not per (agent × codemie).
  • The user story says "not nagged repeatedly about something I cannot or choose not to change" — a CodeMie release is a change on our side, so re-nagging on it is exactly the failure mode the ticket describes.
  • There is no "supported version" concept anywhere in the new design — that was the OLD behavior we removed. My 3-tuple was quietly re-introducing it through codemieVersion as an implicit epoch.

Fixed in b98efbf:

  • VersionWarningStore.hasWarned(agent, agentVersion) and recordWarning(agent, agentVersion) — 2-tuple, codemieVersion field removed from VersionWarningRecord.
  • BaseAgentAdapter.warnOnceIfUntested() uses the 2-tuple key; the running CodeMie version still appears in the banner text for context (falls back to "unknown" when getCurrentCliVersion() returns null — user still gets the notice) but is no longer part of the lookup.
  • AgentsCheck "Acknowledged / Untested with CodeMie X" still shows the current running version — user-facing display unchanged.
  • spec.md rewritten to reflect the 2-tuple design and the reason for excluding codemieVersion from the key.
  • 2660 unit tests green, including a regression test that asserts codemieVersion is not persisted in the marker record.

Effect: once a user acknowledges claude 2.1.218, they stay silent on every CodeMie release until claude itself ships a new version.

@SleepySML

Copy link
Copy Markdown
Contributor Author

Course correction — constants restored

After discussion with @Evgenii_Kurdakov, the ticket's Description text turned out to be misleading. The intent is not to remove the pinned version constants — it is to make the version check completely non-blocking, while keeping the constants as the reference point.

Fixed in 71722d5:

Restored:

  • CLAUDE_SUPPORTED_VERSION, CODEX_SUPPORTED_VERSION, GEMINI_SUPPORTED_VERSION, KIMI_SUPPORTED_VERSION and their _MINIMUM_SUPPORTED_VERSION counterparts across all 4 plugin files.
  • AgentMetadata.supportedVersion / minimumSupportedVersion fields.
  • VersionCompatibilityResult interface and BaseAgentAdapter.checkVersionCompatibility() method.
  • install --supported resolves to metadata.supportedVersion (as before).
  • Default install claude / install codex resolves to supported version (backend-compat sensitive).
  • update for claude uses checkVersionCompatibility for the target version.
  • tests/setup/agent-build-setup.ts back to CLAUDE_SUPPORTED_VERSION-driven install for predictable integration-test binary.

Kept from the non-blocking refactor:

  • BaseAgentAdapter.run() no longer throws / prompts / exits on any version condition.
  • ACP silentMode no longer throws on isBelowMinimum — just logs and proceeds.
  • One-time notice via warnOnceIfUntested(), marker key (agent, installed-version) in ~/.codemie/version-warnings.json.
  • Doctor renders Acknowledged / Untested / Not installed, --reset-version-warnings flag.

New trigger for the notice: fires only when installedVersion !== metadata.supportedVersion. If the user is on the supported version, silent (in tested range). If not, one-time chalk banner + marker records the pair. Subsequent launches of the same pair stay silent, regardless of CodeMie version.

Jira ticket updated with the correction: https://jiraeu.epam.com/browse/EPMCDME-13734 (see latest comment).

Local verification: 2666 unit tests pass, typecheck + lint clean.

Sorry for the churn — should have questioned the "remove entirely" wording earlier when I first read the ticket, instead of taking it at face value.

@mykolanehrych

Copy link
Copy Markdown
Contributor

approved

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