Skip to content
Merged
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
11 changes: 7 additions & 4 deletions cmd/agentctl/cmd_test_subcommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func runTestInstallCodexDesktop() {
}); err != nil {
die(err)
}
fmt.Printf("Codex Desktop installed (version %s)\n", det.Version)
fmt.Printf("%s installed (version %s)\n", codexdesktop.ShortDisplayName, det.Version)
}

func runTestConfigureCodexDesktop() {
Expand Down Expand Up @@ -227,15 +227,18 @@ func runTestOpenFolder(args []string) {
fmt.Println(msg)
}

func openTestFolder(ctx context.Context, s *state.State, p paths.Paths, folder string, opener codexdesktop.Opener, runVSCode func(string, []string) (int, error)) (string, error) {
func openTestFolder(ctx context.Context, s *state.State, p paths.Paths, folder string, launcher codexdesktop.Launcher, runVSCode func(string, []string) (int, error)) (string, error) {
if state.NormalizeFrontendMode(s.FrontendMode) == state.FrontendModeCodexDesktop {
if err := configureTestCodex(p); err != nil {
return "", err
}
if err := codexdesktop.Launch(ctx, folder, opener); err != nil {
if launcher == nil {
launcher = codexdesktop.Launch
}
if err := launcher(ctx, folder); err != nil {
return "", err
}
return fmt.Sprintf("opened %s with Codex Desktop", folder), nil
return fmt.Sprintf("opened %s with %s", folder, codexdesktop.ShortDisplayName), nil
}
if s.VSCode.Path == "" {
return "", fmt.Errorf("VS Code path unknown")
Expand Down
9 changes: 5 additions & 4 deletions cmd/agentctl/cmd_test_subcommands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/agentserver/agentserver-pkg/internal/codex"
"github.com/agentserver/agentserver-pkg/internal/codexdesktop"
"github.com/agentserver/agentserver-pkg/internal/modelproxy"
"github.com/agentserver/agentserver-pkg/internal/paths"
"github.com/agentserver/agentserver-pkg/internal/state"
Expand All @@ -21,8 +22,8 @@ func TestOpenTestFolderCodexDesktopUsesDeepLinkAndWritesConfig(t *testing.T) {
var opened string
runnerCalled := false

msg, err := openTestFolder(context.Background(), s, p, `C:\Project Folder`, func(url string) error {
opened = url
msg, err := openTestFolder(context.Background(), s, p, `C:\Project Folder`, func(_ context.Context, folder string) error {
opened = codexdesktop.ThreadURL(folder)
return nil
}, func(string, []string) (int, error) {
runnerCalled = true
Expand All @@ -40,7 +41,7 @@ func TestOpenTestFolderCodexDesktopUsesDeepLinkAndWritesConfig(t *testing.T) {
if !strings.Contains(opened, "Project+Folder") {
t.Fatalf("path not encoded: %q", opened)
}
if !strings.Contains(msg, "with Codex Desktop") {
if !strings.Contains(msg, "with ChatGPT / Codex") {
t.Fatalf("msg=%q", msg)
}
b, err := os.ReadFile(p.CodexConfigFile)
Expand Down Expand Up @@ -73,7 +74,7 @@ func TestOpenTestFolderMinimalVSCodeUsesRunner(t *testing.T) {
var gotArgs []string
openerCalled := false

msg, err := openTestFolder(context.Background(), s, p, filepath.Join(dir, "work"), func(string) error {
msg, err := openTestFolder(context.Background(), s, p, filepath.Join(dir, "work"), func(context.Context, string) error {
openerCalled = true
return nil
}, func(codeExe string, args []string) (int, error) {
Expand Down
4 changes: 2 additions & 2 deletions cmd/agentctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ USAGE:
P13.4 verification subcommands (skip the OAuth steps, exercise everything else):
agentctl test-install-vscode download + run the VS Code Microsoft Store bootstrapper
agentctl test-install-codex-desktop
install Codex Desktop with winget and persist state
install ChatGPT / Codex with winget and persist state
agentctl test-download-codex download codex.exe to %LOCALAPPDATA%\agentserver-app\bin\
agentctl test-configure write settings.json + config.toml + setx + install extensions
(assumes VS Code already detected; uses local proxy key)
agentctl test-configure-codex-desktop
write Codex config + local proxy key for Codex Desktop
write Codex config + local proxy key for ChatGPT / Codex
agentctl test-open-folder <path>
launch VS Code with our user-data-dir + that folder
agentctl test-mark-complete write onboarding.status = complete so launcher takes the
Expand Down
76 changes: 59 additions & 17 deletions cmd/launcher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ type completedServeInput struct {
InstallDir string
Options launcherOptions
OpenBrowser func(string) error
LaunchFrontend func(context.Context, *state.State) error
TrayApp tray.App
PreferredConsoleInstance console.InstanceInfo
}

Expand All @@ -269,6 +271,17 @@ func serveCompletedConsole(ctx context.Context, in completedServeInput) error {
if openBrowser == nil {
openBrowser = browser.Open
}
launchFrontend := in.LaunchFrontend
if launchFrontend == nil {
launchFrontend = func(ctx context.Context, current *state.State) error {
return launchCompletedFrontend(ctx, current, in.Paths, sec,
in.InstallDir,
joinExe(in.InstallDir, "token-refresher.exe"),
joinExe(in.InstallDir, "agentserver-app.vsix"),
nil,
nil)
}
}
slaveManager, err := newCompletedSlaveManager(in)
if err != nil {
return err
Expand Down Expand Up @@ -318,16 +331,7 @@ func serveCompletedConsole(ctx context.Context, in completedServeInput) error {
OpenURL: openBrowser,
SelectFolder: folderpicker.Select,
OpenFrontend: func(ctx context.Context) error {
current, err := in.State.Load()
if err != nil {
return err
}
return launchCompletedFrontend(ctx, current, in.Paths, sec,
in.InstallDir,
joinExe(in.InstallDir, "token-refresher.exe"),
joinExe(in.InstallDir, "agentserver-app.vsix"),
nil,
nil)
return launchCompletedFrontendAndRecord(ctx, in.State, launchFrontend)
},
Quit: func() {
go srv.Shutdown(context.Background())
Expand Down Expand Up @@ -362,7 +366,10 @@ func serveCompletedConsole(ctx context.Context, in completedServeInput) error {

base := fmt.Sprintf("http://127.0.0.1:%d", port)
trayCtx, stopTray := context.WithCancel(ctx)
trayApp := tray.New(preferredIconPath(in.InstallDir))
trayApp := in.TrayApp
if trayApp == nil {
trayApp = tray.New(preferredIconPath(in.InstallDir))
}
trayActions := tray.Actions{
OpenDashboard: func() {
runAsyncLauncherAction("open console page", func() error {
Expand Down Expand Up @@ -789,7 +796,7 @@ func updateTrayOnce(ctx context.Context, app tray.App, ctrl trayConsoleControlle
func trayStateFromConsole(st console.State) tray.State {
frontendName := strings.TrimSpace(st.FrontendName)
if frontendName == "" {
frontendName = "Codex Desktop"
frontendName = codexdesktop.ShortDisplayName
}
state := tray.State{
Tooltip: "星池指挥官\n额度暂不可用",
Expand Down Expand Up @@ -921,20 +928,52 @@ func launchCompletedInstall(ctx context.Context, codeExe string, p paths.Paths,
}

func startCompletedConsole(ctx context.Context, launcherExe string) error {
return startCompletedConsoleWithStarter(ctx, launcherExe, startDetachedProcess)
}

func startCompletedConsoleWithStarter(ctx context.Context, launcherExe string, start func(string, ...string) error) error {
if ctx != nil {
if err := ctx.Err(); err != nil {
return err
}
}
cmd := exec.Command(launcherExe)
return start(launcherExe, "--background")
}

func startDetachedProcess(exe string, args ...string) error {
cmd := exec.Command(exe, args...)
cmd.Stdin = nil
cmd.Stdout = nil
cmd.Stderr = nil
process.HideWindow(cmd)
return cmd.Start()
}

func launchCompletedFrontend(ctx context.Context, s *state.State, p paths.Paths, sec secrets.Store, installDir string, tokenRefresherExe string, embeddedVSIXPath string, codexOpen codexdesktop.Opener, opencodeLaunch func(context.Context, opencodedesktop.LaunchOptions) error) error {
func launchCompletedFrontendAndRecord(ctx context.Context, store *state.Store, launch func(context.Context, *state.State) error) error {
current, err := store.Load()
if err != nil {
return ui.SafeFrontendStateReadError(err)
}
launchErr := launch(ctx, current)
safeLaunchErr := ui.SafeFrontendLaunchError(current.FrontendMode, launchErr)
frontendError := ""
if safeLaunchErr != nil {
frontendError = safeLaunchErr.Error()
}
persistErr := store.Update(func(latest *state.State) error {
latest.FrontendError = frontendError
return nil
})
if persistErr != nil {
if launchErr != nil {
return ui.SafeFrontendLaunchError(current.FrontendMode, errors.Join(launchErr, persistErr))
}
return ui.SafeFrontendStatePersistenceError(persistErr)
}
return safeLaunchErr
}

func launchCompletedFrontend(ctx context.Context, s *state.State, p paths.Paths, sec secrets.Store, installDir string, tokenRefresherExe string, embeddedVSIXPath string, codexLaunch codexdesktop.Launcher, opencodeLaunch func(context.Context, opencodedesktop.LaunchOptions) error) error {
mode := state.NormalizeFrontendMode(s.FrontendMode)
if mode == state.FrontendModeMinimalVSCode {
if s.VSCode.Path == "" {
Expand All @@ -948,7 +987,7 @@ func launchCompletedFrontend(ctx context.Context, s *state.State, p paths.Paths,
if mode == state.FrontendModeOpenCodeDesktop {
return launchCompletedOpenCodeDesktop(ctx, s, p, sec, installDir, tokenRefresherExe, opencodeLaunch)
}
return launchCompletedCodexDesktop(ctx, s, p, sec, installDir, tokenRefresherExe, codexOpen)
return launchCompletedCodexDesktop(ctx, s, p, sec, installDir, tokenRefresherExe, codexLaunch)
}

func launchCompletedOpenCodeDesktop(ctx context.Context, s *state.State, p paths.Paths, sec secrets.Store, installDir string, tokenRefresherExe string, launcher func(context.Context, opencodedesktop.LaunchOptions) error) error {
Expand Down Expand Up @@ -1004,7 +1043,7 @@ func launcherLocalProxyBearerToken(p paths.Paths) (string, error) {
return modelaccess.EnsureLocalProxyToken(modelaccess.DefaultLocalProxyTokenPath(p.InstallRoot))
}

func launchCompletedCodexDesktop(ctx context.Context, s *state.State, p paths.Paths, sec secrets.Store, installDir string, tokenRefresherExe string, opener codexdesktop.Opener) error {
func launchCompletedCodexDesktop(ctx context.Context, s *state.State, p paths.Paths, sec secrets.Store, installDir string, tokenRefresherExe string, launcher codexdesktop.Launcher) error {
localProxyToken, err := launcherLocalProxyBearerToken(p)
if err != nil {
return err
Expand Down Expand Up @@ -1034,7 +1073,10 @@ func launchCompletedCodexDesktop(ctx context.Context, s *state.State, p paths.Pa
if tokenRefresherExe != "" {
_ = tokenrefresh.StartDaemon(tokenRefresherExe)
}
return codexdesktop.Launch(ctx, "", opener)
if launcher == nil {
launcher = codexdesktop.Launch
}
return launcher(ctx, "")
}

func configureCompletedLoomDriver(p paths.Paths, s *state.State, sec secrets.Store, installDir string) error {
Expand Down
Loading
Loading