name: ssh-console
description: |
  AI と人間が共有する SSH コンソール。タスクに 1 つの PTY セッションを開き、
  両者がコマンドを打ち、出力を見られる。長時間の対話作業、TUI が必要な
  操作 (vim/top/less/tmux 等)、複数ラウンドの調査に向く。

  選ぶべき場合: 「リモートサーバーで色々確認したい」「ログを tail しながら作業」
  「対話的に shell を触りたい」
  選ぶべきでない場合: 1 コマンドの単発実行 (ssh-ops piece が適切)、ファイル転送だけ

  事前条件:
  - admin が config.yaml で ssh.enabled: true / ssh.console.enabled: true を設定済み
  - 利用する SSH 接続が登録され、TOFU host key 検証が完了している
  - ジョブ owner に接続への grant がある
triggers:
  keywords: ["対話", "shell", "console", "ターミナル", "tmux", "vim", "tail", "対話的"]
max_movements: 80
initial_movement: interact

movements:
  - name: interact
    persona: ops-operator
    instruction: |
      ## 詳細ドキュメント (必ず最初に読む)
      ReadToolDoc({name: "SshConsoleEnsure"}) で 3 ツール (Ensure / Send / Snapshot) の
      完全な仕様と典型 flow が見られる。引数と return shape、TUI 操作のコツ、エラー
      コードのリカバリ手順まで網羅。alias なので SshConsoleSend / SshConsoleSnapshot
      でも同じ doc が返る。SshListConnections は ReadToolDoc({name: "SshListConnections"})。

      ## 標準 flow
      0. ユーザーが Console タブから既にセッションを開いていることがある。その場合は
         connection_id を省略して SshConsoleSnapshot({}) で現在の画面を確認し、そのまま
         SshConsoleSend で続ける (改めて Ensure し直す必要はない)。"no live session" が
         返ってきたら下の手順で自分で開く
      1. タスク本文を読み、どのリモートホストでどんな作業をするか把握する
      2. connection_id (UUID) がタスク本文に無ければ SshListConnections({}) で発見する
         - **必ず id フィールドを使う**。label ("terminal" など) や host ("192.168.1.x" など) を connection_id として渡してはいけない
         - UUID を覚えていないからといって**勝手に UUID をでっち上げない** — 必ず SshListConnections で確認する
      3. SshConsoleEnsure({connection_id}) でセッションを開く (冪等)
      4. SshConsoleSend / SshConsoleSnapshot を呼ぶ
         - **2 回目以降の呼び出しでは connection_id を省略するのが推奨** (active session が自動採用される)
         - ジョブ間で UUID を覚え直す必要がなくなる

      ## 使い方の要点
      - 1 行コマンド: SshConsoleSend({input: "ls -la\n"})  — connection_id は省略
      - 連続入力 (heredoc / 複数行 stdin): input に \n 含めて送る
      - TUI に入る: SshConsoleSend({input: "vim test.txt\n", wait_ms: 1000}) → SshConsoleSnapshot で画面確認
      - control 文字: \x03 Ctrl-C / \x04 Ctrl-D / \x1b Esc / \t Tab を input にそのまま含めて送れる
      - vim 抜ける: SshConsoleSend({input: "\x1b:q!\n"})

      ## エラーリカバリ
      - "this task already has an active session on connection X" → 表示されている X を connection_id に使う (or 省略する)。
        本当に別接続に切り替えたいときだけ SshConsoleEnsure({connection_id, force_replace: true})
      - "this task has an active session on connection X, not Y" → 同上 (Send/Snapshot 側のエラー)
      - "no live session for this task" → 初回 ensure が必要。SshConsoleEnsure({connection_id}) を呼ぶ

      ## ファイル転送 (SFTP, PTY とは独立)
      - 設定ファイルを置いて反映したい / リモートのログや成果物を手元で解析したい場合は
        SshUpload / SshDownload を使う。これらは SFTP 経路で動き、active console session
        とは別チャンネルなので PTY を閉じる必要はない (転送後に SshConsoleSend で
        リロードコマンドを送ればよい)
      - リモートパスは接続の remote_path_prefix 配下のみ。ローカルパスは workspace の
        output/ または input/ 配下を使う。詳細・エラーコードは ReadToolDoc({name: "SshUpload"})
        / ReadToolDoc({name: "SshDownload"})

      ## 調べ物 (Web 検索)
      - 不明なコマンド・オプション、エラーメッセージ、設定手順が出てきたら WebSearch で調べてよい。
        ヒットしたページや公式 docs の本文は WebFetch で読む。JS レンダリングや操作が要るページは BrowseWeb。
      - インストーラ / 設定テンプレート / tarball を URL から取得して配信したいときは DownloadFile で
        workspace の output/ または input/ に落とし、SshUpload でリモートへ送る
      - 検索結果を鵜呑みにしてリモートで破壊的コマンドを実行しない。出典を確認し、不可逆操作は user に確認する

      ## 注意
      - shell 状態 (cd / env / foreground プロセス) はタスク内で維持される。毎ターン cd し直す必要なし
      - 機密値はコマンド文字列に直接書かない (audit log に hash で残る)
      - 大量出力で screen_after が切れた場合は SshConsoleSnapshot({kind: "scrollback"}) で全文取得
      - command_rejected が出たら admin に許可パターン追加を相談する (ローカルで回避してはいけない)

      ## 終了
      - 完了: complete({status: "success", result: "..."})
      - 中断: complete({status: "aborted", abort_reason: "..."})
      - 確認待ち: complete({status: "needs_user_input", missing_info: "...", why_no_default: "..."})
    default_next: COMPLETE
    rules: []
