#!/usr/bin/env bash
# Ledger birth record for agent sessions. Sourced by the PATH shim that launches
# claude / codex / cursor-agent, and run before the shim execs the real binary,
# so the entry exists on disk before the session can die.
#
# Contract for readers: docs/agent-session-ledger.md (schemaVersion 1).
#
# No subprocess may be spawned that a PATH shim could intercept (there is a `git`
# shim in front of the real git), and nothing here may abort the launch.

agent_ledger_dir() {
  printf '%s' "${AGENT_SESSIONS_DIR:-$HOME/.local/state/agent-sessions}"
}

_agent_ledger_json() {
  local s=$1 c escaped i
  s=${s//\\/\\\\}
  s=${s//\"/\\\"}
  s=${s//$'\t'/\\t}
  s=${s//$'\n'/\\n}
  s=${s//$'\r'/\\r}
  # A control byte anywhere in a path or ref name makes the whole entry unparseable,
  # which silently drops the session from recovery.
  for i in {1..31}; do
    case $i in 9 | 10 | 13) continue ;; esac
    printf -v c '\\x%02x' "$i"
    printf -v c '%b' "$c"
    printf -v escaped '\\u%04x' "$i"
    s=${s//"$c"/"$escaped"}
  done
  printf -v _alg_json '"%s"' "$s"
}

_agent_ledger_json_or_null() {
  if [[ -z ${1:-} ]]; then _alg_json=null; else _agent_ledger_json "$1"; fi
}

# Walks up from $1 to the first directory holding .git, then reads HEAD without
# invoking git. Sets _alg_repo_root, _alg_branch, _alg_worktree.
_agent_ledger_git() {
  _alg_repo_root=""
  _alg_branch=""
  _alg_worktree="false"
  local dir=$1 gitpath head_file line
  while [[ -n $dir && $dir != "/" ]]; do
    gitpath="$dir/.git"
    if [[ -d $gitpath ]]; then
      _alg_repo_root=$dir
      head_file="$gitpath/HEAD"
      break
    fi
    if [[ -f $gitpath ]]; then
      # `gitdir: <path>` — a linked worktree or a submodule.
      _alg_repo_root=$dir
      _alg_worktree="true"
      read -r _ line <"$gitpath" 2>/dev/null || line=""
      [[ $line == /* ]] || line="$dir/$line"
      head_file="$line/HEAD"
      break
    fi
    dir=${dir%/*}
  done
  [[ -n ${head_file:-} && -r ${head_file:-} ]] || return 0
  read -r line <"$head_file" 2>/dev/null || return 0
  if [[ $line == "ref: refs/heads/"* ]]; then
    _alg_branch=${line#ref: refs/heads/}
  elif [[ -n $line ]]; then
    _alg_branch="detached:${line:0:12}"
  fi
}

_agent_ledger_nonce() {
  local nonce
  read -r nonce </proc/sys/kernel/random/uuid 2>/dev/null || return 1
  nonce=${nonce//-/}
  [[ $nonce =~ ^[0-9a-f]{32}$ ]] || return 1
  printf '%s' "$nonce"
}

# agent_ledger_birth <runtime> [human-tmux-socket] [human-reap-identity] — prints ledger id.
agent_ledger_birth() {
  local runtime=$1 human_tmux_socket="${2:-}" human_reap_identity="${3:-}" human_tmux_session=""
  local _alg_json q_id q_runtime q_host q_boot q_cwd q_repo q_project q_branch q_tty
  local q_parent q_human_session q_human_socket q_human_reap_identity
  local dir sessions_dir id stamp started_at rand cwd tty entry tmp reserve attempt
  local parent_id="${AGENT_LEDGER_ID:-}"
  local launched_by='null' parent='null'

  # A dedicated systemd-owned tmux server intentionally breaks the Unix parent chain.
  # Preserve launch evidence that is authoritative before that handoff: the factory marker
  # wins, otherwise an inherited ledger id proves this session was launched by that agent.
  if [[ ${FACTORY_ADW:-} == 1 ]]; then
    launched_by='"factory"'
  elif [[ -n "$parent_id" ]]; then
    launched_by='"agent"'
    _agent_ledger_json "$parent_id"
    parent=$_alg_json
  fi

  dir="${AGENT_SESSIONS_DIR:-$HOME/.local/state/agent-sessions}"
  sessions_dir="$dir/sessions"
  # -m 700 on creation: a later chmod leaves the socket dir world-traversable in between,
  # and a reachable socket is a live agent terminal.
  # shellcheck disable=SC2174
  mkdir -p -m 700 "$sessions_dir" "$dir/sock" 2>/dev/null || return 1
  chmod 700 "$dir" 2>/dev/null || true

  TZ=UTC printf -v stamp '%(%Y%m%dT%H%M%S)T' -1
  for ((attempt = 0; attempt < 16; attempt++)); do
    rand="$(_agent_ledger_nonce)" || return 1
    id="${runtime}-${stamp}Z-${rand}"
    reserve="$sessions_dir/.$id.reserve"
    if mkdir "$reserve" 2>/dev/null; then
      if [[ ! -e "$sessions_dir/$id.json" ]]; then
        break
      fi
      rmdir "$reserve" 2>/dev/null || return 1
    fi
    reserve=""
  done
  [[ -n "$reserve" && -d "$reserve" ]] || return 1
  [[ -n "$human_tmux_socket" ]] && human_tmux_session="$id"

  cwd=$PWD
  _agent_ledger_git "$cwd"

  tty=""
  [[ -t 0 ]] && tty=$(readlink "/proc/$$/fd/0" 2>/dev/null) || true
  [[ $tty == /dev/* ]] || tty=""

  local boot_id=""
  read -r boot_id </proc/sys/kernel/random/boot_id 2>/dev/null || boot_id=""

  local project=""
  [[ -n $_alg_repo_root ]] && project=${_alg_repo_root##*/}

  _agent_ledger_json "$id"; q_id=$_alg_json
  _agent_ledger_json "$runtime"; q_runtime=$_alg_json
  _agent_ledger_json "${HOSTNAME:-unknown}"; q_host=$_alg_json
  _agent_ledger_json_or_null "$boot_id"; q_boot=$_alg_json
  _agent_ledger_json "$cwd"; q_cwd=$_alg_json
  _agent_ledger_json_or_null "$_alg_repo_root"; q_repo=$_alg_json
  _agent_ledger_json_or_null "$project"; q_project=$_alg_json
  _agent_ledger_json_or_null "$_alg_branch"; q_branch=$_alg_json
  _agent_ledger_json_or_null "$tty"; q_tty=$_alg_json
  _agent_ledger_json_or_null "$parent_id"; q_parent=$_alg_json
  _agent_ledger_json_or_null "$human_tmux_session"; q_human_session=$_alg_json
  _agent_ledger_json_or_null "$human_tmux_socket"; q_human_socket=$_alg_json
  _agent_ledger_json_or_null "$human_reap_identity"; q_human_reap_identity=$_alg_json

  TZ=UTC printf -v started_at '%(%Y-%m-%dT%H:%M:%S)TZ' -1
  IFS= read -r -d '' entry <<JSON || :
{
  "schemaVersion": 1,
  "ledgerId": $q_id,
  "runtime": $q_runtime,
  "startedAt": "$started_at",
  "host": $q_host,
  "bootId": $q_boot,
  "cwd": $q_cwd,
  "repoRoot": $q_repo,
  "project": $q_project,
  "branch": $q_branch,
  "worktree": $_alg_worktree,
  "tty": $q_tty,
  "launcherPid": $$,
  "parentLedgerId": $q_parent,
  "parent": $parent,
  "launchedBy": $launched_by,
  "account": null,
  "enrolledBy": "shim",
  "mux": { "kind": null, "socket": null, "target": null },
  "tmuxSession": $q_human_session,
  "tmuxSocket": $q_human_socket,
  "tmuxReapIdentity": $q_human_reap_identity,
  "pid": null,
  "pidStartTicks": null,
  "cpuTicks": null,
  "sessionId": null,
  "transcriptPath": null,
  "lastActiveAt": null,
  "lastHeartbeatAt": null,
  "finishedAt": null,
  "finishReason": null
}
JSON

  tmp="$sessions_dir/.$id.$$.tmp"
  printf '%s\n' "$entry" >"$tmp" 2>/dev/null || { rmdir "$reserve" 2>/dev/null; return 1; }
  if ! ln "$tmp" "$sessions_dir/$id.json" 2>/dev/null; then
    rm -f "$tmp"
    rmdir "$reserve" 2>/dev/null
    return 1
  fi
  rm -f "$tmp"
  rmdir "$reserve" 2>/dev/null || return 1

  printf '%s' "$id"
}
