summaryrefslogtreecommitdiffhomepage
path: root/bin/up
blob: a47135cc522a058a575eb4237a5eb781d5657cae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"

# Pass host user identity so the container runs as the same UID/GID
export HOST_UID="$(id -u)"
export HOST_GID="$(id -g)"
export HOST_USER="$(whoami)"

# --- DEBUG=1 convenience flag ------------------------------------
# `DEBUG=1 bin/up` turns on full LLM debug logging (request/response
# bodies) AND the per-step usage split (cache read/write tokens), and
# routes the JSON log files into `logging/` at the project root. That
# directory is mounted into the container at /app/logging via the
# `.:/app` bind, so the files land on the host where you can
# `tail -F logging/*.json` without `docker exec`. `logging/` is
# gitignored.
#
# It only sets DEFAULTS -- any DISPATCH_DEBUG_* var you set explicitly
# still wins, so fine-grained control (e.g. a custom verbosity or a
# different log dir) is preserved.
if [ -n "${DEBUG:-}" ] && [ "$DEBUG" != "0" ]; then
    : "${DISPATCH_DEBUG_LLM:=1}"
    : "${DISPATCH_DEBUG_USAGE:=1}"
    : "${DISPATCH_DEBUG_LLM_DIR:=/app/logging}"
fi

# Debug-logger pass-through. docker-compose only forwards env vars that are
# (a) set in the parent shell AND (b) referenced in docker-compose.yml's
# `environment:` block -- so without this `export` step the variables would
# be invisible to the container even when the user prefixes the command with
# DISPATCH_DEBUG_LLM=1. We re-export here (rather than relying on the shell's
# inline `VAR=... cmd` syntax) so it works whether the user sets them inline,
# in their shell rc, or via `.env`.
#
# All variables default to empty -- when unset, the logger short-circuits and
# does nothing.
export DISPATCH_DEBUG_LLM="${DISPATCH_DEBUG_LLM:-}"
export DISPATCH_DEBUG_LLM_VERBOSITY="${DISPATCH_DEBUG_LLM_VERBOSITY:-}"
export DISPATCH_DEBUG_USAGE="${DISPATCH_DEBUG_USAGE:-}"
# Container-side log directory. Empty => the logger uses its built-in default
# (/tmp/dispatch/llm-debug). DEBUG=1 sets it to /app/logging (see above).
export DISPATCH_DEBUG_LLM_DIR="${DISPATCH_DEBUG_LLM_DIR:-}"

# Pre-create the debug log directory owned by the host user. Without this,
# docker auto-creates the bind-mount source as root on first start, and the
# container's bun process (running as host UID) then gets EACCES on every log
# write -- silent except for `[dispatch-debug] Failed to write ...: EACCES`
# lines drowned in stderr.
#
# The host path depends on which container dir the logger targets:
#   - /app/<sub>  -> the project bind-mount, host path $PROJECT_DIR/<sub>
#                   (already host-owned; a plain mkdir is enough).
#   - otherwise   -> the dedicated /tmp/dispatch/llm-debug volume; may have
#                   been root-created by a prior run, so fix ownership.
case "${DISPATCH_DEBUG_LLM_DIR}" in
    /app/*)
        HOST_LOG_DIR="$PROJECT_DIR/${DISPATCH_DEBUG_LLM_DIR#/app/}"
        mkdir -p "$HOST_LOG_DIR" 2>/dev/null || true
        ;;
    *)
        HOST_LOG_DIR=/tmp/dispatch/llm-debug
        mkdir -p "$HOST_LOG_DIR" 2>/dev/null || true
        if [ ! -O "$HOST_LOG_DIR" ]; then
            current_owner=$(stat -c '%U' "$HOST_LOG_DIR" 2>/dev/null || echo "unknown")
            echo "bin/up: $HOST_LOG_DIR is owned by '$current_owner', fixing ownership to '$HOST_USER'..."
            sudo chown -R "$HOST_UID:$HOST_GID" "$HOST_LOG_DIR"
        fi
        ;;
esac

if [ -n "${DISPATCH_DEBUG_LLM}" ]; then
    echo "bin/up: debug logging ON -> ${DISPATCH_DEBUG_LLM_DIR:-/tmp/dispatch/llm-debug} (host: $HOST_LOG_DIR)"
fi

# Start all services
docker compose -f "$PROJECT_DIR/docker-compose.yml" up "$@"