114 lines
2.7 KiB
Go
114 lines
2.7 KiB
Go
package orch
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"ai-workflow-skill/packages/coord-core/protocol"
|
|
"ai-workflow-skill/packages/coord-core/store"
|
|
)
|
|
|
|
func Execute(args []string, stdout, stderr io.Writer) int {
|
|
cmd := NewRootCmd()
|
|
cmd.SetOut(stdout)
|
|
cmd.SetErr(stderr)
|
|
cmd.SetArgs(args)
|
|
|
|
if err := cmd.Execute(); err != nil {
|
|
jsonOutput := hasJSONFlag(args)
|
|
renderError(stdout, stderr, jsonOutput, err)
|
|
return exitCodeForError(err)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func exitCodeForError(err error) int {
|
|
var cliErr *protocol.CLIError
|
|
if errors.As(err, &cliErr) {
|
|
return cliErr.ExitCode
|
|
}
|
|
|
|
switch {
|
|
case isUsageError(err):
|
|
return 30
|
|
case errors.Is(err, store.ErrLeaseConflict):
|
|
return 20
|
|
case errors.Is(err, store.ErrRunNotFound), errors.Is(err, store.ErrTaskNotFound), errors.Is(err, store.ErrThreadNotFound), errors.Is(err, store.ErrMessageNotFound):
|
|
return 40
|
|
case errors.Is(err, store.ErrInvalidInput), errors.Is(err, store.ErrInvalidState), errors.Is(err, store.ErrNoActiveLease):
|
|
return 30
|
|
default:
|
|
return 50
|
|
}
|
|
}
|
|
|
|
func errorCodeForError(err error) string {
|
|
var cliErr *protocol.CLIError
|
|
if errors.As(err, &cliErr) {
|
|
return cliErr.Code
|
|
}
|
|
|
|
switch {
|
|
case isUsageError(err):
|
|
return "invalid_input"
|
|
case errors.Is(err, store.ErrLeaseConflict):
|
|
return "conflict"
|
|
case errors.Is(err, store.ErrRunNotFound), errors.Is(err, store.ErrTaskNotFound), errors.Is(err, store.ErrThreadNotFound), errors.Is(err, store.ErrMessageNotFound):
|
|
return "not_found"
|
|
case errors.Is(err, store.ErrInvalidInput):
|
|
return "invalid_input"
|
|
case errors.Is(err, store.ErrInvalidState), errors.Is(err, store.ErrNoActiveLease):
|
|
return "invalid_state"
|
|
default:
|
|
return "internal_error"
|
|
}
|
|
}
|
|
|
|
func renderError(stdout, stderr io.Writer, jsonOutput bool, err error) {
|
|
message := errorMessage(err)
|
|
if jsonOutput {
|
|
_ = protocol.WriteJSON(stdout, protocol.Error{
|
|
OK: false,
|
|
Error: protocol.ErrorPayload{
|
|
Code: errorCodeForError(err),
|
|
Message: message,
|
|
},
|
|
})
|
|
return
|
|
}
|
|
|
|
_, _ = fmt.Fprintln(stderr, message)
|
|
}
|
|
|
|
func errorMessage(err error) string {
|
|
var cliErr *protocol.CLIError
|
|
if errors.As(err, &cliErr) {
|
|
return cliErr.Message
|
|
}
|
|
return err.Error()
|
|
}
|
|
|
|
func hasJSONFlag(args []string) bool {
|
|
for _, arg := range args {
|
|
if arg == "--json" {
|
|
return true
|
|
}
|
|
if strings.HasPrefix(arg, "--json=") {
|
|
return !strings.HasSuffix(arg, "=false")
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isUsageError(err error) bool {
|
|
message := err.Error()
|
|
return strings.HasPrefix(message, "required flag(s)") ||
|
|
strings.HasPrefix(message, "unknown flag:") ||
|
|
strings.HasPrefix(message, "unknown command ") ||
|
|
strings.Contains(message, " accepts ") ||
|
|
strings.Contains(message, "invalid argument ")
|
|
}
|