#!/usr/bin/env bash set -euo pipefail server_url="${BOSS_SERVER_URL:-http://127.0.0.1:43210}" session_file="${BOSS_SESSION_FILE:-.boss-session}" usage() { cat <<'EOF' Usage: boss_chat.sh sessions boss_chat.sh create [title] boss_chat.sh send "" [session_id] boss_chat.sh status [session_id] Environment: BOSS_SERVER_URL Default: http://127.0.0.1:43210 BOSS_SESSION_FILE Default: .boss-session EOF } require_tools() { command -v curl >/dev/null 2>&1 || { echo "curl is required" >&2 exit 1 } command -v node >/dev/null 2>&1 || { echo "node is required" >&2 exit 1 } } request() { local method="$1" local path="$2" local body="${3:-}" if [[ -n "$body" ]]; then curl -fsS -X "$method" "$server_url$path" -H 'Content-Type: application/json' -d "$body" else curl -fsS -X "$method" "$server_url$path" fi } json_payload() { local key="$1" local value="$2" node -e 'const [key, value] = process.argv.slice(1); process.stdout.write(JSON.stringify({ [key]: value }));' "$key" "$value" } json_message_payload() { local value="$1" node -e 'const value = process.argv[1]; process.stdout.write(JSON.stringify({ content: value, channel: "cli" }));' "$value" } json_get() { local expr="$1" node -e "const fs = require('fs'); const data = JSON.parse(fs.readFileSync(0, 'utf8')); const result = (${expr}); if (result === undefined || result === null) process.exit(2); if (typeof result === 'string') process.stdout.write(result); else process.stdout.write(JSON.stringify(result, null, 2));" } save_session_id() { printf '%s' "$1" > "$session_file" } load_session_id() { if [[ -f "$session_file" ]]; then cat "$session_file" return 0 fi return 1 } create_session() { local title="${1:-Boss 主控对话}" local payload payload="$(request POST /api/sessions "$(json_payload title "$title")")" local session_id session_id="$(printf '%s' "$payload" | json_get "data.session.id")" save_session_id "$session_id" printf '%s\n' "$payload" } command="${1:-}" shift || true if [[ -z "$command" ]]; then usage exit 1 fi require_tools case "$command" in sessions) request GET /api/sessions | node -e 'const fs=require("fs"); const data=JSON.parse(fs.readFileSync(0,"utf8")); for (const session of data) console.log(`${session.id}\t${session.status}\t${session.title}`);' ;; create) create_session "${1:-Boss 主控对话}" ;; send) message="${1:-}" if [[ -z "$message" ]]; then echo "Missing message." >&2 exit 1 fi session_id="${2:-}" if [[ -z "$session_id" ]]; then session_id="$(load_session_id || true)" fi if [[ -z "$session_id" ]]; then session_json="$(create_session "Boss 主控对话")" session_id="$(printf '%s' "$session_json" | json_get "data.session.id")" fi request POST "/api/sessions/$session_id/messages" "$(json_message_payload "$message")" printf '\n' save_session_id "$session_id" ;; status) session_id="${1:-}" if [[ -z "$session_id" ]]; then session_id="$(load_session_id || true)" fi if [[ -z "$session_id" ]]; then echo "No session id found. Run create or send first." >&2 exit 1 fi request GET "/api/sessions/$session_id" printf '\n' ;; *) usage exit 1 ;; esac