v0.4.0 12ae076

debug-remote-attach.sh RawHistoryFolder

1#!/usr/bin/env bash
2set -euo pipefail
3
4usage() {
5  cat <<'USAGE' >&2
6Usage: scripts/debug-remote-attach.sh [--mode stdio|quic|default] [--session NAME] [--duration 8s] [--vev-bin PATH] user@host
7
8Runs a real remote attach smoke/debug attempt under a PTY, captures local and
9remote vev versions, and stores local/remote log tails around the attempt.
10
11Examples:
12  scripts/debug-remote-attach.sh user@example-host
13  scripts/debug-remote-attach.sh --session work user@example-host
14  scripts/debug-remote-attach.sh --mode quic user@example-host
15  go build -o /tmp/vev-debug . && scripts/debug-remote-attach.sh --vev-bin /tmp/vev-debug user@example-host
16
17Notes:
18  - The command times out intentionally if attach succeeds and stays interactive.
19  - Exit 124 from timeout is treated as a likely successful attach if no early
20    vev/ssh error is captured; inspect the bundle for confirmation.
21  - The remote host must be reachable by SSH for log collection.
22  - The attach attempt unsets VEV so the smoke test can run from inside vev.
23USAGE
24}
25
26mode="default"
27session=""
28duration="8s"
29vev_bin="${VEV_BIN:-vev}"
30while [[ $# -gt 0 ]]; do
31  case "$1" in
32    --mode)
33      mode="${2:-}"; shift 2 ;;
34    --session)
35      session="${2:-}"; shift 2 ;;
36    --duration)
37      duration="${2:-}"; shift 2 ;;
38    --vev-bin)
39      vev_bin="${2:-}"; shift 2 ;;
40    -h|--help)
41      usage; exit 0 ;;
42    --)
43      shift; break ;;
44    -*)
45      echo "unknown option: $1" >&2; usage; exit 2 ;;
46    *)
47      break ;;
48  esac
49done
50
51if [[ $# -ne 1 ]]; then
52  usage
53  exit 2
54fi
55case "$mode" in
56  default|stdio|quic) ;;
57  *) echo "invalid --mode $mode (want default, stdio, or quic)" >&2; exit 2 ;;
58esac
59
60target="$1"
61attach_target="$target"
62if [[ -n "$session" ]]; then
63  attach_target="$target:$session"
64fi
65
66repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
67out_dir="${TMPDIR:-/tmp}/vev-remote-attach-$(date +%Y%m%d-%H%M%S)"
68mkdir -p "$out_dir"
69
70local_state="${XDG_STATE_HOME:-$HOME/.local/state}/vev"
71
72# All persisted and displayed command output passes through this filter. Keep
73# diagnostic counters while removing the target, local home, network addresses,
74# and common key material labels from bundles that may be shared.
75redact() {
76  sed -E \
77    -e "s|${target//\/\\/\\}|[target]|g" \
78    -e "s|${HOME//\/\\/\\}|[home]|g" \
79    -e 's/([[:alnum:]_.-]+@)?([[:alnum:]_.-]+\.)+[[:alpha:]]{2,}/[host]/g' \
80    -e 's/([0-9]{1,3}\.){3}[0-9]{1,3}/[address]/g' \
81    -e 's/([[:xdigit:]]{1,4}:){2,}[[:xdigit:]:]*/[address]/g' \
82    -e 's/(private[ _-]?key|ssh-rsa|ssh-ed25519|ecdsa-sha2-[^[:space:]]*)/[redacted-key]/Ig'
83}
84
85redact_file() {
86  local raw="$1" dest="$2"
87  redact <"$raw" >"$dest" || true
88  rm -f "$raw"
89}
90
91run_capture() {
92  local name="$1" raw_out raw_err status
93  shift
94  raw_out="$out_dir/.$name.out.raw"
95  raw_err="$out_dir/.$name.err.raw"
96  status=0
97  {
98    printf '$'
99    printf ' %q' "$@"
100    printf '\n'
101    "$@"
102  } >"$raw_out" 2>"$raw_err" || status=$?
103  redact_file "$raw_out" "$out_dir/$name.out"
104  redact_file "$raw_err" "$out_dir/$name.err"
105  if [[ "$status" -ne 0 ]]; then printf '%s\n' "$status" >"$out_dir/$name.exit"; fi
106}
107
108copy_local_logs() {
109  local label="$1" raw
110  mkdir -p "$out_dir/local-$label"
111  if [[ -d "$local_state" ]]; then
112    find "$local_state" -maxdepth 1 -type f -name 'vev*.log' -print0 2>/dev/null | while IFS= read -r -d '' f; do
113      raw="$out_dir/local-$label/.$(basename "$f").raw"
114      tail -n 200 "$f" >"$raw" || true
115      redact_file "$raw" "$out_dir/local-$label/$(basename "$f")"
116    done
117  fi
118}
119
120copy_remote_logs() {
121  local label="$1" raw_out="$out_dir/remote-$1/.logs.out.raw" raw_err="$out_dir/remote-$1/.logs.err.raw"
122  mkdir -p "$out_dir/remote-$label"
123  ssh -o BatchMode=yes -o ConnectTimeout=8 "$target" 'state="${XDG_STATE_HOME:-$HOME/.local/state}/vev"; if [ -d "$state" ]; then for f in "$state"/vev*.log; do [ -e "$f" ] || continue; echo "===== $f ====="; tail -n 200 "$f"; done; fi' \
124    >"$raw_out" 2>"$raw_err" || true
125  redact_file "$raw_out" "$out_dir/remote-$label/logs.out"
126  redact_file "$raw_err" "$out_dir/remote-$label/logs.err"
127}
128
129printf 'debug bundle: %s\n' "$out_dir"
130printf 'mode: %s\nduration: %s\n' "$mode" "$duration" >"$out_dir/summary.txt"
131
132raw_git="$out_dir/.git.raw"
133(
134  cd "$repo_root"
135  git rev-parse --show-toplevel
136  git rev-parse --short HEAD
137  git status --short
138) >"$raw_git" 2>&1 || true
139redact_file "$raw_git" "$out_dir/git.txt"
140
141run_capture local-version "$vev_bin" --version
142raw_remote_version_out="$out_dir/.remote-version.out.raw"
143raw_remote_version_err="$out_dir/.remote-version.err.raw"
144ssh -o BatchMode=yes -o ConnectTimeout=8 "$target" 'set -e; command -v vev; vev --version; pgrep -a vev || true; state="${XDG_STATE_HOME:-$HOME/.local/state}/vev"; echo "state=$state"' \
145  >"$raw_remote_version_out" 2>"$raw_remote_version_err" || echo "$?" >"$out_dir/remote-version.exit"
146redact_file "$raw_remote_version_out" "$out_dir/remote-version.out"
147redact_file "$raw_remote_version_err" "$out_dir/remote-version.err"
148
149copy_local_logs before
150copy_remote_logs before
151
152attach_log_raw="$out_dir/.attach.typescript.raw"
153attach_err_raw="$out_dir/.attach.err.raw"
154attach_stdout_raw="$out_dir/.attach.stdout.raw"
155cmd=("$vev_bin" attach "$attach_target")
156if [[ "$mode" == "default" ]]; then
157  env_cmd=(env -u VEV -u VEV_REMOTE_TRANSPORT)
158else
159  env_cmd=(env -u VEV "VEV_REMOTE_TRANSPORT=$mode")
160fi
161
162set +e
163if command -v script >/dev/null 2>&1; then
164  printf -v attach_cmd '%q ' "${cmd[@]}"
165  "${env_cmd[@]}" timeout "$duration" script -q -e -c "$attach_cmd" "$attach_log_raw" >"$attach_stdout_raw" 2>"$attach_err_raw"
166else
167  "${env_cmd[@]}" timeout "$duration" "${cmd[@]}" >"$attach_stdout_raw" 2>"$attach_err_raw"
168fi
169attach_status=$?
170set -e
171redact_file "$attach_stdout_raw" "$out_dir/attach.stdout"
172redact_file "$attach_err_raw" "$out_dir/attach.err"
173if [[ -e "$attach_log_raw" ]]; then redact_file "$attach_log_raw" "$out_dir/attach.typescript"; fi
174printf '%s\n' "$attach_status" >"$out_dir/attach.exit"
175
176copy_local_logs after
177copy_remote_logs after
178
179{
180  echo "debug bundle: $out_dir"
181  echo "attach exit: $attach_status"
182  echo "local version:"
183  sed 's/^/  /' "$out_dir/local-version.out" 2>/dev/null || true
184  echo "remote version:"
185  sed 's/^/  /' "$out_dir/remote-version.out" 2>/dev/null || true
186  if [[ -s "$out_dir/attach.err" ]]; then
187    echo "attach stderr:"
188    sed 's/^/  /' "$out_dir/attach.err" | tail -40
189  fi
190  echo "recent local after logs:"
191  find "$out_dir/local-after" -maxdepth 1 -type f -print0 2>/dev/null | while IFS= read -r -d '' f; do
192    echo "  --- $(basename "$f") ---"
193    tail -20 "$f" | sed 's/^/    /'
194  done
195  echo "recent remote after logs:"
196  tail -80 "$out_dir/remote-after/logs.out" 2>/dev/null | sed 's/^/  /' || true
197} | tee -a "$out_dir/summary.txt"
198
199if [[ "$attach_status" -eq 124 ]]; then
200  echo "attach timed out after $duration; this often means the interactive attach stayed alive. Inspect $out_dir for protocol/log errors."
201  exit 0
202fi
203exit "$attach_status"

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close