Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions cmd/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/agentuity/go-common/tui"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.design/x/clipboard"
)

var authCmd = &cobra.Command{
Expand Down Expand Up @@ -72,17 +73,31 @@ Examples:
os.Exit(1)
}

authURL := fmt.Sprintf("%s/auth/cli", appUrl)

copyMessage := "Copy the following code:"
openMessage := "Then open the url in your browser (or press ENTER) and paste the code:"

err := clipboard.Init()
if err == nil {
clipboard.Write(clipboard.FmtText, []byte(otp))
copyMessage = "This code was copied to your clipboard:"
openMessage = "Open the url in your browser (or press ENTER) and paste the code from your clipboard:"
}

body := tui.Paragraph(
"Copy the following code:",
copyMessage,
tui.Bold(otp),
"Then open the url in your browser and paste the code:",
tui.Link("%s/auth/cli", appUrl),
openMessage,
tui.Link("%s", authURL),
tui.Muted("This code will expire in 60 seconds"),
)

tui.ShowBanner("Login to Agentuity", body, false)

tui.ShowSpinner("Waiting for login to complete...", func() {
go util.PromptBrowserOpen(logger, authURL)

authResult, err := auth.PollForLoginCompletion(ctx, logger, apiUrl, otp)
if err != nil {
if isCancelled(ctx) {
Expand Down
10 changes: 7 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.10.0
github.com/zijiren233/yaml-comment v0.2.2
golang.design/x/clipboard v0.7.1
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.32.1
Expand Down Expand Up @@ -56,6 +57,9 @@ require (
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476 // indirect
golang.org/x/image v0.28.0 // indirect
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f // indirect
golang.org/x/term v0.30.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
Expand Down Expand Up @@ -130,9 +134,9 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/net v0.38.0
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0
golang.org/x/text v0.24.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0
golang.org/x/text v0.26.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/grpc v1.71.0 // indirect
Expand Down
20 changes: 14 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
golang.design/x/clipboard v0.7.1 h1:OEG3CmcYRBNnRwpDp7+uWLiZi3hrMRJpE9JkkkYtz2c=
golang.design/x/clipboard v0.7.1/go.mod h1:i5SiIqj0wLFw9P/1D7vfILFK0KHMk7ydE72HRrUIgkg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
Expand All @@ -302,6 +304,12 @@ golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476 h1:Wdx0vgH5Wgsw+lF//LJKmWOJBLWX6nprsMqnf99rYDE=
golang.org/x/exp/shiny v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f h1:/n+PL2HlfqeSiDCuhdBbRNlGS/g2fM4OHufalHaTVG8=
golang.org/x/mobile v0.0.0-20250606033058-a2a15c67f36f/go.mod h1:ESkJ836Z6LpG6mTVAhA48LpfW/8fNR0ifStlH2axyfg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand All @@ -314,8 +322,8 @@ golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -329,16 +337,16 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
Expand Down
2 changes: 1 addition & 1 deletion internal/bundler/groq.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ func init() {
Before: generateEnvGuard("GROQ_API_KEY", generateGatewayEnvGuard("GROQ_API_KEY", "process.env.AGENTUITY_SDK_KEY", "GROQ_BASE_URL", "groq")),
},
}
}
}
42 changes: 41 additions & 1 deletion internal/util/browser.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package util

import (
"bufio"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -164,7 +165,7 @@
}
if !skip {
if berr := browser.OpenURL(u.String()); berr != nil {
returnErr = fmt.Errorf("failed to open browser: %s", err)
returnErr = fmt.Errorf("failed to open browser: %w", berr)
return
}
}
Expand All @@ -189,3 +190,42 @@

return returnErr
}

// PromptBrowserOpen prompts the user to press Enter to open a browser to the given URL.
// It handles display detection on Linux and provides appropriate user feedback.
func PromptBrowserOpen(logger interface{ Error(string, ...interface{}) }, url string) {
var skipOpen bool
if runtime.GOOS == "linux" {
// if we don't have a display, we can't open a browser most likely
if _, ok := os.LookupEnv("DISPLAY"); !ok {
skipOpen = true
}
}

fmt.Println()
if skipOpen {
fmt.Print(tui.Secondary("Press Enter to continue, or Ctrl+C to skip: "))
} else {
fmt.Print(tui.Secondary("Press Enter to open browser, or Ctrl+C to skip: "))
}

reader := bufio.NewReader(os.Stdin)
reader.ReadLine()

if !skipOpen {
if err := browser.OpenURL(url); err != nil {
logger.Error("Failed to open browser: %v", err)
} else {
// Clear previous line and move cursor up to remove the "Press Enter..." prompt
fmt.Print("\r\033[K\033[A\r\033[K")
tui.ShowSuccess("Browser opened!")
fmt.Println()
}
} else {
// Clear the prompt and show the URL for manual opening (and the loading spinner)
fmt.Print("\r\033[K")
fmt.Println(tui.Muted("Please visit the URL manually:"))
fmt.Println(tui.Link(url))

Check failure on line 228 in internal/util/browser.go

View workflow job for this annotation

GitHub Actions / Build and Test (blacksmith-4vcpu-ubuntu-2204)

non-constant format string in call to github.com/agentuity/go-common/tui.Link
fmt.Println()
Comment on lines +225 to +229
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

tui.Link called with a dynamic format string triggers vet failure.

go vet (and your pipeline) flags fmt.Println(tui.Link(url)) because url is treated as a format string and may contain % tokens. Pass a constant format instead:

-		fmt.Println(tui.Link(url))
+		fmt.Println(tui.Link("%s", url))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Clear the prompt and show the URL for manual opening (and the loading spinner)
fmt.Print("\r\033[K")
fmt.Println(tui.Muted("Please visit the URL manually:"))
fmt.Println(tui.Link(url))
fmt.Println()
// Clear the prompt and show the URL for manual opening (and the loading spinner)
fmt.Print("\r\033[K")
fmt.Println(tui.Muted("Please visit the URL manually:"))
- fmt.Println(tui.Link(url))
+ fmt.Println(tui.Link("%s", url))
fmt.Println()
🧰 Tools
🪛 GitHub Check: Build and Test (blacksmith-4vcpu-ubuntu-2204)

[failure] 228-228:
non-constant format string in call to github.com/agentuity/go-common/tui.Link

🪛 golangci-lint (1.64.8)

228-228: printf: non-constant format string in call to github.com/agentuity/go-common/tui.Link

(govet)

🤖 Prompt for AI Agents
In internal/util/browser.go around lines 225 to 229, the call to tui.Link with
url as a dynamic string causes go vet to fail because url may contain percent
signs interpreted as format verbs. To fix this, change the call to pass a
constant format string and url as an argument, ensuring tui.Link treats url as
data, not a format string.

}
}
Loading