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
17 changes: 12 additions & 5 deletions .agents/skills/uloop-launch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,19 @@ uloop launch --quit

- Prints detected Unity version
- Prints project path
- If Unity is already running, focuses the existing window
- If launching, prints when it is waiting for Unity CLI Loop server readiness
- If launching, waits until Unity finishes startup and the CLI can connect to the project
- When launch readiness completes, returns JSON with:
- `Success`: whether launch readiness completed
- If Unity is already running, focuses the existing window and verifies tool readiness
- If launching or restarting, prints when it is waiting for Unity CLI Loop server readiness
- If launching or restarting, waits until Unity finishes startup and the CLI can connect to the project
- Successful launch, restart, existing-process, and quit paths return JSON with:
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
- `Success`: whether the command completed
- `Ready`: whether Unity CLI Loop is ready for commands
- `ServerReady`: whether the Unity CLI Loop server accepted requests
- `ProjectIpcReady`: whether the project IPC path accepted tool requests
- `AlreadyRunning`: whether an existing Unity process was reused
- `Launched`: whether this command launched a Unity process
- `Restarted`: whether this command stopped an existing process and launched a new one
- `Quit`: whether this command stopped Unity without launching a new process
- `PreviousProcessId`: process ID stopped by restart or quit, when available
- `CurrentProcessId`: current Unity process ID, when available
- `ProjectRoot`: resolved project root
- `Message`: readiness summary
17 changes: 12 additions & 5 deletions .claude/skills/uloop-launch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,19 @@ uloop launch --quit

- Prints detected Unity version
- Prints project path
- If Unity is already running, focuses the existing window
- If launching, prints when it is waiting for Unity CLI Loop server readiness
- If launching, waits until Unity finishes startup and the CLI can connect to the project
- When launch readiness completes, returns JSON with:
- `Success`: whether launch readiness completed
- If Unity is already running, focuses the existing window and verifies tool readiness
- If launching or restarting, prints when it is waiting for Unity CLI Loop server readiness
- If launching or restarting, waits until Unity finishes startup and the CLI can connect to the project
- Successful launch, restart, existing-process, and quit paths return JSON with:
- `Success`: whether the command completed
- `Ready`: whether Unity CLI Loop is ready for commands
- `ServerReady`: whether the Unity CLI Loop server accepted requests
- `ProjectIpcReady`: whether the project IPC path accepted tool requests
- `AlreadyRunning`: whether an existing Unity process was reused
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
- `Launched`: whether this command launched a Unity process
- `Restarted`: whether this command stopped an existing process and launched a new one
- `Quit`: whether this command stopped Unity without launching a new process
- `PreviousProcessId`: process ID stopped by restart or quit, when available
- `CurrentProcessId`: current Unity process ID, when available
- `ProjectRoot`: resolved project root
- `Message`: readiness summary
17 changes: 12 additions & 5 deletions Packages/src/Editor/CliOnlyTools~/Launch/Skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,19 @@ uloop launch --quit

- Prints detected Unity version
- Prints project path
- If Unity is already running, focuses the existing window
- If launching, prints when it is waiting for Unity CLI Loop server readiness
- If launching, waits until Unity finishes startup and the CLI can connect to the project
- When launch readiness completes, returns JSON with:
- `Success`: whether launch readiness completed
- If Unity is already running, focuses the existing window and verifies tool readiness
- If launching or restarting, prints when it is waiting for Unity CLI Loop server readiness
- If launching or restarting, waits until Unity finishes startup and the CLI can connect to the project
- Successful launch, restart, existing-process, and quit paths return JSON with:
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
- `Success`: whether the command completed
- `Ready`: whether Unity CLI Loop is ready for commands
- `ServerReady`: whether the Unity CLI Loop server accepted requests
- `ProjectIpcReady`: whether the project IPC path accepted tool requests
- `AlreadyRunning`: whether an existing Unity process was reused
- `Launched`: whether this command launched a Unity process
- `Restarted`: whether this command stopped an existing process and launched a new one
- `Quit`: whether this command stopped Unity without launching a new process
- `PreviousProcessId`: process ID stopped by restart or quit, when available
- `CurrentProcessId`: current Unity process ID, when available
- `ProjectRoot`: resolved project root
- `Message`: readiness summary
Comment thread
coderabbitai[bot] marked this conversation as resolved.
2 changes: 1 addition & 1 deletion Packages/src/Editor/Domain/CliConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace io.github.hatayama.UnityCliLoop.Domain
public static class CliConstants
{
public const string EXECUTABLE_NAME = "uloop";
public const string MINIMUM_REQUIRED_CLI_VERSION = "3.0.0-beta.27";
public const string MINIMUM_REQUIRED_CLI_VERSION = "3.0.0-beta.28";
public const string MINIMUM_REQUIRED_CLI_RELEASE_TAG = CLI_RELEASE_TAG_PREFIX + MINIMUM_REQUIRED_CLI_VERSION;
public const string VERSION_FLAG = "--version";
public const string SHORT_VERSION_FLAG = "-v";
Expand Down
2 changes: 1 addition & 1 deletion cli/contract.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"schemaVersion": 1,
"cliVersion": "3.0.0-beta.27"
"cliVersion": "3.0.0-beta.28"
}
27 changes: 19 additions & 8 deletions cli/internal/cli/launch.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
var (
findRunningUnityProcessForLaunch = findRunningUnityProcess
focusUnityProcessForLaunch = focusUnityProcess
killUnityProcessForLaunch = killUnityProcess
resolveUnityExecutablePathForLaunch = resolveUnityExecutablePath
waitForUnityLockfileForLaunch = waitForUnityLockfile
waitForToolReadinessForLaunch = waitForToolReadiness
Expand Down Expand Up @@ -203,22 +204,27 @@ func runLaunch(ctx context.Context, options launchOptions, startPath string, std
if runningProcess != nil {
if !options.restart && !options.quit {
logLaunchExistingFocus(ctx, projectRoot, runningProcess.pid)
writeFormat(stdout, "Unity is already running for %s (PID: %d)\n", projectRoot, runningProcess.pid)
return 0
spinner := newLaunchSpinner(stdout, stderr)
defer spinner.Stop()
writeLaunchReadinessWait(stdout, spinner)
if err := waitForToolReadinessForLaunch(ctx, projectRoot); err != nil {
writeClassifiedError(stderr, err, errorContext{projectRoot: projectRoot, command: launchCommandName})
return 1
}
spinner.Stop()
return writeExistingLaunchReadyResponse(stdout, stderr, projectRoot, runningProcess.pid)
}
if err := killUnityProcess(runningProcess.pid); err != nil {
if err := killUnityProcessForLaunch(runningProcess.pid); err != nil {
writeClassifiedError(stderr, err, errorContext{projectRoot: projectRoot, command: launchCommandName})
return 1
}
if options.quit {
writeFormat(stdout, "Unity process stopped (PID: %d)\n", runningProcess.pid)
return 0
return writeLaunchQuitResponse(stdout, stderr, projectRoot, &runningProcess.pid, launchStoppedMessage)
}
}

if options.quit {
writeLine(stdout, "No Unity process is running for this project.")
return 0
return writeLaunchQuitResponse(stdout, stderr, projectRoot, nil, launchNoProcessMessage)
}

removedStaleTemp, err := cleanStaleUnityTemp(projectRoot)
Expand Down Expand Up @@ -258,6 +264,7 @@ func runLaunch(ctx context.Context, options launchOptions, startPath string, std
writeClassifiedError(stderr, err, errorContext{projectRoot: projectRoot, command: launchCommandName})
return 1
}
currentPid := command.Process.Pid
if err := command.Process.Release(); err != nil {
writeClassifiedError(stderr, err, errorContext{projectRoot: projectRoot, command: launchCommandName})
return 1
Expand All @@ -272,7 +279,11 @@ func runLaunch(ctx context.Context, options launchOptions, startPath string, std
return 1
}
spinner.Stop()
return writeLaunchReadyResponse(stdout, stderr, projectRoot)
var previousPid *int
if runningProcess != nil {
previousPid = &runningProcess.pid
}
return writeLaunchedReadyResponse(stdout, stderr, projectRoot, previousPid, currentPid)
}

func newUnityLaunchCommand(unityPath string, launchArgs []string) *exec.Cmd {
Expand Down
85 changes: 69 additions & 16 deletions cli/internal/cli/launch_ready.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,26 @@ import (
)

const (
launchReadinessMessage = "Waiting for Unity CLI Loop server readiness..."
launchReadyMessage = "Unity CLI Loop is ready."
launchReadinessMessage = "Waiting for Unity CLI Loop server readiness..."
launchReadyMessage = "Unity CLI Loop is ready."
launchAlreadyRunningReadyMessage = "Unity is already running and ready."
launchStoppedMessage = "Unity process stopped."
launchNoProcessMessage = "No Unity process is running for this project."
)

type launchReadyResponse struct {
Success bool `json:"Success"`
Ready bool `json:"Ready"`
ServerReady bool `json:"ServerReady"`
ProjectIpcReady bool `json:"ProjectIpcReady"`
Message string `json:"Message"`
Success bool `json:"Success"`
Ready bool `json:"Ready"`
ServerReady bool `json:"ServerReady"`
ProjectIpcReady bool `json:"ProjectIpcReady"`
AlreadyRunning bool `json:"AlreadyRunning"`
Launched bool `json:"Launched"`
Restarted bool `json:"Restarted"`
Quit bool `json:"Quit"`
PreviousProcessId *int `json:"PreviousProcessId,omitempty"`
CurrentProcessId *int `json:"CurrentProcessId,omitempty"`
ProjectRoot string `json:"ProjectRoot"`
Message string `json:"Message"`
}

func writeLaunchReadinessWait(stdout io.Writer, spinner *terminalSpinner) {
Expand All @@ -25,17 +35,60 @@ func writeLaunchReadinessWait(stdout io.Writer, spinner *terminalSpinner) {
}
}

func writeLaunchReadyResponse(stdout io.Writer, stderr io.Writer, projectRoot string) int {
response := launchReadyResponse{
Success: true,
Ready: true,
ServerReady: true,
ProjectIpcReady: true,
Message: launchReadyMessage,
}
func writeExistingLaunchReadyResponse(stdout io.Writer, stderr io.Writer, projectRoot string, currentPid int) int {
return writeLaunchResponse(stdout, stderr, launchReadyResponse{
Success: true,
Ready: true,
ServerReady: true,
ProjectIpcReady: true,
AlreadyRunning: true,
CurrentProcessId: &currentPid,
ProjectRoot: projectRoot,
Message: launchAlreadyRunningReadyMessage,
})
}

func writeLaunchedReadyResponse(
stdout io.Writer,
stderr io.Writer,
projectRoot string,
previousPid *int,
currentPid int,
) int {
return writeLaunchResponse(stdout, stderr, launchReadyResponse{
Success: true,
Ready: true,
ServerReady: true,
ProjectIpcReady: true,
Launched: true,
Restarted: previousPid != nil,
PreviousProcessId: previousPid,
CurrentProcessId: &currentPid,
ProjectRoot: projectRoot,
Message: launchReadyMessage,
})
}

func writeLaunchQuitResponse(
stdout io.Writer,
stderr io.Writer,
projectRoot string,
previousPid *int,
message string,
) int {
return writeLaunchResponse(stdout, stderr, launchReadyResponse{
Success: true,
Quit: true,
PreviousProcessId: previousPid,
ProjectRoot: projectRoot,
Message: message,
})
}

func writeLaunchResponse(stdout io.Writer, stderr io.Writer, response launchReadyResponse) int {
payload, err := json.Marshal(response)
if err != nil {
writeClassifiedError(stderr, err, errorContext{projectRoot: projectRoot, command: launchCommandName})
writeClassifiedError(stderr, err, errorContext{projectRoot: response.ProjectRoot, command: launchCommandName})
return 1
}
writeJSON(stdout, payload)
Expand Down
Loading
Loading