diff --git a/go.mod b/go.mod index 8bfa8338..0ad6b634 100644 --- a/go.mod +++ b/go.mod @@ -103,7 +103,7 @@ require ( github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.16.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect diff --git a/internal/bundler/upgrade.go b/internal/bundler/upgrade.go index 9c728aa8..1e7fb9e0 100644 --- a/internal/bundler/upgrade.go +++ b/internal/bundler/upgrade.go @@ -9,6 +9,7 @@ import ( "github.com/Masterminds/semver" "github.com/agentuity/cli/internal/util" "github.com/agentuity/go-common/tui" + "github.com/pelletier/go-toml/v2" ) type breakingChange struct { @@ -18,7 +19,7 @@ type breakingChange struct { Version string } -var jsBreakingChanges = []breakingChange{ +var breakingChanges = []breakingChange{ { Runtime: "bunjs", Version: "<0.0.106", @@ -31,14 +32,66 @@ var jsBreakingChanges = []breakingChange{ Title: "🚫 JS SDK Breaking Change 🚫", Message: "The JS SDK type signatures for AgentRequest have changed to be async functions. Please see the v0.0.106 Changelog for how to update your code.\n\n" + tui.Link("https://agentuity.dev/Changelog/sdk-js#v00106") + "\n\nPlease npm upgrade @agentuity/sdk, fix your types and ensure your code passes type checking and then re-run this command again.", }, + { + Runtime: "uv", + Version: "<0.0.82", + Title: "🚫 Python SDK Breaking Changes 🚫", + Message: "The Python SDK type signatures for AgentRequest have changed to be async functions. Please see the v0.0.82 Changelog for how to update your code.\n\n" + tui.Link("https://agentuity.dev/Changelog/sdk-py#v0082") + "\n\nPlease run `uv add agentuity -U` fix your types and ensure your code passes type checking and then re-run this command again.", + }, } type packageJSON struct { Version string `json:"version"` } +type UVPackage struct { + Name string `json:"name"` + Version string `json:"version"` +} + +type UVLockfile struct { + Packages []UVPackage `toml:"package"` +} + func checkForBreakingChanges(ctx BundleContext, language string, runtime string) error { + ctx.Logger.Trace("Checking for breaking changes in %s, runtime: %s", language, runtime) switch language { + case "python": + uvlock := filepath.Join(ctx.ProjectDir, "uv.lock") + ctx.Logger.Trace("Checking for breaking changes in %s, exists: %t", uvlock, util.Exists(uvlock)) + if util.Exists(uvlock) { + var lockfile UVLockfile + content, err := os.Open(uvlock) + if err != nil { + return err + } + if err := toml.NewDecoder(content).Decode(&lockfile); err != nil { + return err + } + for _, pkg := range lockfile.Packages { + ctx.Logger.Trace("Checking for breaking changes in %s", pkg.Name) + if pkg.Name == "agentuity" { + currentVersion := semver.MustParse(pkg.Version) + for _, change := range breakingChanges { + if change.Runtime != runtime { + continue + } + c, err := semver.NewConstraint(change.Version) + if err != nil { + return fmt.Errorf("error parsing semver constraint %s: %w", change.Version, err) + } + if c.Check(currentVersion) { + if tui.HasTTY { + tui.ShowBanner(change.Title, change.Message, true) + os.Exit(1) + } else { + ctx.Logger.Fatal(change.Message) + } + } + } + } + } + } case "javascript": pkgjson := filepath.Join(ctx.ProjectDir, "node_modules", "@agentuity", "sdk", "package.json") if util.Exists(pkgjson) { @@ -51,7 +104,7 @@ func checkForBreakingChanges(ctx BundleContext, language string, runtime string) return err } currentVersion := semver.MustParse(pkg.Version) - for _, change := range jsBreakingChanges { + for _, change := range breakingChanges { if change.Runtime != runtime { continue }