mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-12 12:18:55 +02:00
* feat(daemon): add minimum Claude Code version check during runtime registration The daemon now validates the detected agent CLI version against a minimum requirement before registering a runtime. Claude Code requires >= 2.0.0 (when --output-format stream-json and --permission-mode bypassPermissions were introduced). Older versions are skipped with a warning log, preventing silent failures. Closes #569 * feat(daemon): add minimum Codex CLI version check (>= 0.100.0) The `codex app-server --listen stdio://` flag was introduced in v0.100.0. Older versions lack this flag and fail silently. Add codex to the MinVersions map so the daemon skips outdated codex CLIs with a clear warning, matching the existing Claude version check. Refs #490
68 lines
2.0 KiB
Go
68 lines
2.0 KiB
Go
package agent
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
)
|
|
|
|
// MinVersions defines the minimum required CLI version for each agent type.
|
|
// Versions below these will be rejected during daemon registration.
|
|
var MinVersions = map[string]string{
|
|
"claude": "2.0.0",
|
|
"codex": "0.100.0", // app-server --listen stdio:// added in 0.100.0
|
|
}
|
|
|
|
// semver holds a parsed semantic version (major.minor.patch).
|
|
type semver struct {
|
|
Major, Minor, Patch int
|
|
}
|
|
|
|
// versionRe matches version strings like "2.1.100", "v2.0.0", or
|
|
// "2.1.100 (Claude Code)" — it extracts the first three numeric components.
|
|
var versionRe = regexp.MustCompile(`v?(\d+)\.(\d+)\.(\d+)`)
|
|
|
|
// parseSemver extracts a semver from a version string.
|
|
func parseSemver(raw string) (semver, error) {
|
|
m := versionRe.FindStringSubmatch(raw)
|
|
if m == nil {
|
|
return semver{}, fmt.Errorf("cannot parse version %q", raw)
|
|
}
|
|
major, _ := strconv.Atoi(m[1])
|
|
minor, _ := strconv.Atoi(m[2])
|
|
patch, _ := strconv.Atoi(m[3])
|
|
return semver{Major: major, Minor: minor, Patch: patch}, nil
|
|
}
|
|
|
|
// lessThan returns true if v < other.
|
|
func (v semver) lessThan(other semver) bool {
|
|
if v.Major != other.Major {
|
|
return v.Major < other.Major
|
|
}
|
|
if v.Minor != other.Minor {
|
|
return v.Minor < other.Minor
|
|
}
|
|
return v.Patch < other.Patch
|
|
}
|
|
|
|
// CheckMinVersion validates that detectedVersion meets the minimum for agentType.
|
|
// Returns nil if the version is acceptable or no minimum is defined.
|
|
func CheckMinVersion(agentType, detectedVersion string) error {
|
|
minRaw, ok := MinVersions[agentType]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
min, err := parseSemver(minRaw)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid minimum version %q for %s: %w", minRaw, agentType, err)
|
|
}
|
|
detected, err := parseSemver(detectedVersion)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot parse detected %s version %q: %w", agentType, detectedVersion, err)
|
|
}
|
|
if detected.lessThan(min) {
|
|
return fmt.Errorf("%s version %s is below minimum required %s — please upgrade", agentType, detectedVersion, minRaw)
|
|
}
|
|
return nil
|
|
}
|