#!/bin/bash

# omarchy:summary=Launch the default coding agent in a terminal
# omarchy:args=[--inline] [--pick]
# omarchy:examples=omarchy agent | omarchy agent --inline

inline=false
pick=false

# Flags only. A bare prompt would shadow the subcommands under this group, so
# prompts go through omarchy-agent-prompt, which passes one here as --prompt.
while (($#)); do
  case "$1" in
    --inline)
      inline=true
      shift
      ;;
    --pick)
      pick=true
      shift
      ;;
    --prompt)
      prompt=${2:?--prompt needs a value}
      shift 2
      ;;
    *)
      echo "Unexpected argument: $1" >&2
      echo "To pass a prompt: omarchy agent prompt \"$*\"" >&2
      exit 1
      ;;
  esac
done

# Agents refuse to remember trust for $HOME, so launches from the keybinding or
# menu start in the work directory instead of re-asking on every session.
[[ $PWD == "$HOME" && -d $HOME/Work ]] && cd "$HOME/Work"

agent=$(omarchy-default-agent)

# Omarchy ships without a default, so there is nothing to launch until one is
# picked. --pick offers the choice instead of the error, which is what the
# keybinding wants: a keypress that opens nothing explains nothing.
if [[ -z $agent ]]; then
  [[ $pick == "true" ]] && exec omarchy-menu summon setup.default.agent
  echo "Choose default agent with: omarchy default agent <name>" >&2
  exit 1
fi

# OpenClaw's launcher sets OpenClaw up when the package became the seed before
# this user's OpenClaw moved, so with the package a missing command is its to fix.
if omarchy-cmd-missing "$agent" && ! { [[ $agent == "openclaw" ]] && omarchy-pkg-present openclaw; }; then
  echo "$agent is not installed. Choose an installed agent with: omarchy default agent <name>" >&2
  exit 1
fi

# Agents launched from the keybinding or menu run unattended, so each one starts
# with its own spelling of "don't stop to ask". Pi and Ori have none to skip.
case "$agent" in
opencode)
  command=(opencode --auto)
  [[ -n ${prompt:-} ]] && command+=(--prompt "$prompt")
  ;;
agy)
  command=(agy --dangerously-skip-permissions)
  [[ -n ${prompt:-} ]] && command+=(--prompt-interactive "$prompt")
  ;;
copilot)
  command=(copilot --allow-all)
  [[ -n ${prompt:-} ]] && command+=(--interactive "$prompt")
  ;;
crush)
  # --yolo belongs to the interactive command only; `crush run` never prompts.
  if [[ -n ${prompt:-} ]]; then
    command=(crush run "$prompt")
  else
    command=(crush --yolo)
  fi
  ;;
claude)
  command=(claude --permission-mode auto)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
grok)
  command=(grok --permission-mode bypassPermissions)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
openclaw)
  # The launcher owns onboarding and the gateway dance: OpenClaw's terminal UI
  # must attach to the running gateway (the embedded `openclaw chat` refuses to
  # start while the gateway owns the state directory). It has no permission
  # prompts to skip, and --message seeds the session while keeping it
  # interactive.
  command=(omarchy-launch-openclaw --tui)
  [[ -n ${prompt:-} ]] && command+=(--message "$prompt")
  ;;
codex)
  command=(codex --approve-for-me)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
cursor-agent)
  # --yolo covers commands only; the workspace trust dialog has its own flag.
  # A one-word prompt naming a subcommand (update, login, help) still runs that
  # subcommand after a bare --, so the agent subcommand is named outright, and
  # -- after it keeps a prompt starting with a dash from being read as an option.
  command=(cursor-agent --yolo --trust)
  [[ -n ${prompt:-} ]] && command+=(agent -- "$prompt")
  ;;
hermes)
  if [[ -n ${prompt:-} ]]; then
    command=(env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=$prompt")
  else
    command=(hermes --yolo)
  fi
  ;;
muse)
  # --approval-mode never skips the tool prompts but keeps Muse's own sandbox.
  command=(muse --approval-mode never)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
omp)
  command=(omp --auto-approve)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
ori)
  # Ori is a harness launcher, and `ori code` is the agent it runs itself.
  # A prompt alone means one headless turn there, printed after the turn ends,
  # so --interactive is what seeds the session with it and keeps the window.
  command=(ori code)
  [[ -n ${prompt:-} ]] && command+=(--interactive --prompt "$prompt")
  ;;
pi)
  command=(pi)
  [[ -n ${prompt:-} ]] && command+=("$prompt")
  ;;
kimi)
  # --prompt is non-interactive print mode only; it cannot combine with --yolo.
  if [[ -n ${prompt:-} ]]; then
    command=(kimi --prompt "$prompt")
  else
    command=(kimi --yolo)
  fi
  ;;
qwen)
  # Bind the value so a prompt starting with a dash stays literal.
  command=(qwen --yolo)
  [[ -n ${prompt:-} ]] && command+=("--prompt-interactive=$prompt")
  ;;
dsh)
  # The browser UI has no prompt option, and the headless profile would run the
  # prompt with full access in a window that closes with its answer, so a
  # prompt goes to the clipboard below instead.
  command=(env DSH_PERMISSION_MODE=danger-full-access dsh web)
  prompt_via_clipboard="DeepSeek Harness"
  ;;
mcode)
  # The TUI has no no-approval flag; permission options belong to exec mode.
  command=(mcode)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
kiro-cli)
  # A positional input seeds the interactive chat; -- keeps a prompt starting
  # with a dash literal.
  command=(kiro-cli chat --trust-all-tools)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
freebuff)
  # Freebuff takes no starting prompt and asks no tool permissions, so a
  # prompt goes to the clipboard below instead.
  command=(freebuff)
  prompt_via_clipboard="Freebuff"
  ;;
kilo)
  # Kilo is built on OpenCode and shares its flags. Bind the prompt so one
  # starting with a dash stays literal.
  command=(kilo --auto)
  [[ -n ${prompt:-} ]] && command+=("--prompt=$prompt")
  ;;
devin)
  # A bare positional is a path that opens Devin Desktop, so the prompt
  # always follows --, which starts an interactive session with it.
  command=(devin --permission-mode dangerous --respect-workspace-trust false)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
amp)
  # Amp takes its first interactive message from piped input; a positional
  # message is for --execute, which exits after one turn. The binary rides in
  # as $0 so a user install below can replace it.
  if [[ -n ${prompt:-} ]]; then
    command=(bash -c 'printf "%s\n" "$1" | exec "$0" --dangerously-allow-all' amp "$prompt")
  else
    command=(amp --dangerously-allow-all)
  fi
  ;;
commandcode)
  # --yolo skips permission prompts and implies --trust. A positional prompt
  # seeds the interactive session; -- keeps one starting with a dash literal.
  command=(commandcode --yolo)
  [[ -n ${prompt:-} ]] && command+=(-- "$prompt")
  ;;
*)
  echo "Unsupported default agent: $agent" >&2
  exit 1
  ;;
esac

# An agent with no way to take a starting prompt still opens, with the prompt
# on the clipboard to paste as its first message, so a prompted launch from the
# agents panel or a crash report is not lost.
if [[ -n ${prompt:-} && -n ${prompt_via_clipboard:-} ]]; then
  printf '%s' "$prompt" | wl-copy
  omarchy-notification-send -g 󰅇 "$(omarchy-i18n agents.promptOnClipboard "$prompt_via_clipboard")" \
    "$(omarchy-i18n agents.promptOnClipboardBody)"
fi

# omarchy-mise-install's wrappers run `mise use` and `mise x`, current ones on
# lines of their own and older ones after an inline variable; either way
# running one installs the tool it wraps. A symlink is the user's own install.
mise_wrapper() {
  [[ ! -L $1 ]] && head -c 4096 "$1" | grep -qaE 'mise (use|x) '
}

# The user's own install in ~/.local/bin, which omarchy-default-agent counts as
# installed, still wins over mise's lazy shim earlier on PATH, which would
# install and run mise's copy instead. Once mise has installed its own, a
# terminal runs that one, so the launcher does too. OpenClaw's command runs its
# launcher, so its prompt is the only argument that could match the name.
user_install="$HOME/.local/bin/$agent"
if [[ $agent != "openclaw" && -f $user_install && -x $user_install ]] &&
  ! mise_wrapper "$user_install" && ! MISE_OFFLINE=1 mise which "$agent" &>/dev/null; then
  for i in "${!command[@]}"; do
    if [[ ${command[i]} == "$agent" ]]; then
      command[i]=$user_install
      break
    fi
  done
fi

# A new session uses the current selection rather than its parent's account
# pin. Explicit provider homes still override the selection. Carry the new pin
# in the command, since terminals launched through uwsm don't inherit our env.
case "$agent" in
claude) home_env="CLAUDE_CONFIG_DIR" ;;
codex) home_env="CODEX_HOME" ;;
grok) home_env="GROK_HOME" ;;
*) home_env="" ;;
esac
if [[ -n $home_env ]]; then
  account_pin="OMARCHY_AGENT_${agent^^}_HOME"
  if [[ -v $account_pin && ${!home_env:-} == "${!account_pin}" ]]; then
    unset "$home_env"
  fi
  unset "$account_pin"
  if [[ -z ${!home_env:-} ]]; then
    home=$(omarchy-agent-account-home "$agent")
    account_env=(env -u "$home_env" "$account_pin=$home")
    [[ -n $home ]] && account_env+=("$home_env=$home")
    command=("${account_env[@]}" "${command[@]}")
  fi
fi

if [[ $inline == "true" ]]; then
  exec "${command[@]}"
else
  # A fixed app-id rather than the default org.omarchy.<binary>, so every agent
  # window shares one class for window rules and themes to single out.
  exec omarchy-launch-tui --app-id=org.omarchy.agent "${command[@]}"
fi
