项目文件夹

文件
wehub-resource-sync f3d80b4628
Auto Release / auto-release (push) Failing after 1s
CI / lint (push) Failing after 0s
CI / screenshot-quality (push) Failing after 3s
CI / pr-policy (push) Has been skipped
CI / test (3.11) (push) Failing after 0s
CI / test (3.12) (push) Failing after 0s
CI / test (3.13) (push) Failing after 3s
CI / coverage (push) Failing after 1s
Legibility / legibility (push) Failing after 3s
chore: import upstream snapshot with attribution
2026-07-13 12:31:48 +08:00

159 行
4.2 KiB
Bash
可执行文件

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
#!/usr/bin/env bash
set -euo pipefail
# Run a real non--print Claude session under tmux, send two prompts, and collect artifacts.
# Usage:
# scripts/run_real_e2e_tmux.sh
# Env:
# PROMPT_ONE / PROMPT_TWO override default prompts
# PERMISSION_MODE override Claude permission mode (default: bypassPermissions)
# SUBMIT_KEY override tmux submit key (default: Enter)
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
if ! command -v tmux >/dev/null 2>&1; then
echo "error: tmux not found. Install it first (e.g. brew install tmux)." >&2
exit 1
fi
if ! command -v uv >/dev/null 2>&1; then
echo "error: uv not found." >&2
exit 1
fi
TS="$(date +%s)"
TRACE_DIR="/tmp/ctap-tmux-simple-$TS"
SESSION="ctap_simple_$TS"
PANE_LOG="/tmp/claude-tap-recordings/tmux-simple-$TS.log"
PERMISSION_MODE="${PERMISSION_MODE:-bypassPermissions}"
PROMPT_ONE="${PROMPT_ONE:-Use the shell tool to run command ls in the current directory, then reply with any 5 filenames only.}"
PROMPT_TWO="${PROMPT_TWO:-Thank you.}"
SUBMIT_KEY="${SUBMIT_KEY:-Enter}"
mkdir -p "$TRACE_DIR" /tmp/claude-tap-recordings
wait_for_prompt() {
local timeout="${1:-60}"
local i=0
while (( i < timeout )); do
if tmux capture-pane -p -S -300 -t "$SESSION" 2>/dev/null | grep -qF ""; then
return 0
fi
sleep 1
((i += 1))
done
return 1
}
wait_for_prompt_in_trace() {
local needle="$1"
local timeout="${2:-120}"
local i=0
while (( i < timeout )); do
local jf
jf="$(ls -1 "$TRACE_DIR"/trace_*.jsonl 2>/dev/null | tail -n1 || true)"
if [[ -n "$jf" ]] && grep -qF "$needle" "$jf"; then
return 0
fi
sleep 1
((i += 1))
done
return 1
}
send_prompt() {
local text="$1"
local key="$2"
tmux send-keys -t "$SESSION" -l "$text"
# Give the TUI a moment to consume the literal input before submit.
sleep 0.2
tmux send-keys -t "$SESSION" "$key"
}
submit_prompt_with_detection() {
local text="$1"
local timeout="${2:-120}"
local attempt
local max_attempts=3
for ((attempt = 1; attempt <= max_attempts; attempt++)); do
send_prompt "$text" "$SUBMIT_KEY"
if wait_for_prompt_in_trace "$text" "$timeout"; then
echo "submit_key=$SUBMIT_KEY attempt=$attempt"
return 0
fi
# If submit did not fire, clear line and retry the same key.
tmux send-keys -t "$SESSION" Escape C-u
sleep 1
done
return 1
}
cleanup() {
tmux capture-pane -S -6000 -p -t "$SESSION" > "$PANE_LOG" 2>/dev/null || true
tmux kill-session -t "$SESSION" >/dev/null 2>&1 || true
}
trap cleanup EXIT
tmux new-session -d -s "$SESSION" -x 160 -y 46
tmux send-keys -t "$SESSION" -l "cd $REPO_ROOT && uv run python -m claude_tap --tap-output-dir $TRACE_DIR --tap-proxy-mode forward -- --permission-mode $PERMISSION_MODE"
tmux send-keys -t "$SESSION" Enter
wait_for_prompt 90 || true
submit_prompt_with_detection "$PROMPT_ONE" 30 || {
echo "error: prompt one not observed in trace jsonl" >&2
exit 2
}
wait_for_prompt 120 || true
submit_prompt_with_detection "$PROMPT_TWO" 30 || {
echo "error: prompt two not observed in trace jsonl" >&2
exit 3
}
wait_for_prompt 90 || true
tmux send-keys -t "$SESSION" -l "/exit"
tmux send-keys -t "$SESSION" Enter
sleep 2
JSONL="$(ls -1 "$TRACE_DIR"/trace_*.jsonl | tail -n1)"
HTML="${JSONL%.jsonl}.html"
if [[ ! -f "$HTML" ]]; then
uv run python - "$JSONL" "$HTML" <<'PY'
import sys
from pathlib import Path
from claude_tap import _generate_html_viewer
_generate_html_viewer(Path(sys.argv[1]), Path(sys.argv[2]))
PY
fi
uv run python - "$JSONL" "$PROMPT_ONE" "$PROMPT_TWO" <<'PY'
import json
import sys
from pathlib import Path
jf = Path(sys.argv[1])
p1 = sys.argv[2]
p2 = sys.argv[3]
text = jf.read_text(encoding="utf-8")
if p1 not in text:
raise SystemExit("assert failed: prompt one missing in jsonl")
if p2 not in text:
raise SystemExit("assert failed: prompt two missing in jsonl")
records = [json.loads(x) for x in text.splitlines() if x.strip()]
msg = [r for r in records if r.get("request", {}).get("path", "").startswith("/v1/messages")]
if len(msg) < 2:
raise SystemExit(f"assert failed: expected >=2 /v1/messages requests, got {len(msg)}")
print(f"assert ok: message_requests={len(msg)}")
PY
echo "TRACE_DIR=$TRACE_DIR"
echo "JSONL=$JSONL"
echo "HTML=$HTML"
echo "PANE_LOG=$PANE_LOG"