feat(scripts): pnpm work + pnpm debug for agent-driven workflows (#1105)

This commit is contained in:
Steven Enamakel
2026-05-02 13:47:38 -07:00
committed by GitHub
parent f8cfe85ee7
commit d28074ca8c
15 changed files with 686 additions and 26 deletions
+46
View File
@@ -0,0 +1,46 @@
# scripts/debug
Agent-friendly wrappers around the project's test runners. Each command runs
the underlying tool with full output **teed to a log file** under
`target/debug-logs/`, while keeping stdout small (summary + failure blocks).
Use `--verbose` on any runner to also stream the raw output.
## Usage
```sh
# Vitest
pnpm debug unit # full suite
pnpm debug unit src/components/Foo.test.tsx # one file (positional pattern)
pnpm debug unit -t "renders empty state" # filter by test name
pnpm debug unit Foo -t "renders empty" --verbose
# WDIO E2E (one spec at a time)
pnpm debug e2e test/e2e/specs/smoke.spec.ts
pnpm debug e2e test/e2e/specs/cron-jobs-flow.spec.ts cron-jobs --verbose
# cargo tests (uses scripts/test-rust-with-mock.sh)
pnpm debug rust
pnpm debug rust json_rpc_e2e
# Inspect saved logs
pnpm debug logs # list 50 most recent
pnpm debug logs last # print most recent (last 400 lines)
pnpm debug logs unit # most recent matching prefix "unit"
pnpm debug logs last --tail 100
```
Logs land in `target/debug-logs/<kind>-<suffix>-<timestamp>.log`. The directory
is created on demand and is safe to delete — nothing else writes there.
## Why
- **Filtering** — positional pattern + `-t "<name>"` for Vitest, single spec
for WDIO; agents don't have to grep the whole tree on every change.
- **Bounded output** — the default summary fits in agent context. Full output
is one `pnpm debug logs last` away.
- **Stable surface** — the runners' flags can churn; this wrapper keeps the
contract small (positional + a couple of flags) so prompts don't break.
The wrappers don't replace the project test runners — they invoke the
underlying tools/scripts with log capture.
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# Dispatcher for `pnpm debug <cmd> <args…>`.
# Agent-friendly wrappers around the project's test/run scripts.
# Commands: unit | e2e | rust | logs
set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
usage() {
cat <<'EOF'
Usage: pnpm debug <command> [args]
Commands:
unit [pattern] [-t "<name>"] [--watch] [--verbose]
Run Vitest. Full log goes to target/debug-logs/unit-<ts>.log;
stdout shows only summary + failure blocks unless --verbose.
e2e <spec> [log-suffix] [--verbose]
Run a single WDIO spec via app/scripts/e2e-run-spec.sh.
Full log goes to target/debug-logs/e2e-<suffix>-<ts>.log.
rust [test-filter] [--verbose]
Run cargo tests with the mock backend (test-rust-with-mock.sh).
Full log goes to target/debug-logs/rust-<ts>.log.
logs [list|<run-id>|last] [--head N | --tail N]
Inspect saved debug-log files. `last` shows the most recent.
Flags common to runners:
--verbose Stream full output to stdout in addition to the log file.
Exit code = the underlying tool's exit code.
EOF
}
cmd="${1:-}"
if [ -z "$cmd" ] || [ "$cmd" = "-h" ] || [ "$cmd" = "--help" ]; then
usage
exit 0
fi
shift
case "$cmd" in
unit|e2e|rust|logs)
exec "$here/${cmd}.sh" "$@"
;;
*)
echo "[debug] unknown command: $cmd" >&2
usage >&2
exit 1
;;
esac
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# e2e.sh <spec> [log-suffix] [--verbose]
# Wraps app/scripts/e2e-run-spec.sh with log capture + summary.
set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib.sh
source "$here/lib.sh"
verbose=0
spec=""
suffix=""
while [ $# -gt 0 ]; do
case "$1" in
--verbose) verbose=1; shift ;;
-*)
echo "[debug:e2e] unknown flag: $1" >&2; exit 1 ;;
*)
if [ -z "$spec" ]; then spec="$1"
elif [ -z "$suffix" ]; then suffix="$1"
else echo "[debug:e2e] unexpected arg: $1" >&2; exit 1
fi
shift ;;
esac
done
if [ -z "$spec" ]; then
echo "Usage: pnpm debug e2e <spec-path> [log-suffix] [--verbose]" >&2
exit 1
fi
repo_root="$(debug_repo_root)"
log_dir="$(debug_log_dir)"
[ -n "$suffix" ] || suffix="$(basename "$spec" .spec.ts)"
safe_suffix="$(basename -- "$suffix")"
safe_suffix="${safe_suffix//[^[:alnum:]._-]/-}"
[ -n "$safe_suffix" ] || safe_suffix="spec"
log="$log_dir/e2e-${safe_suffix}-$(debug_timestamp).log"
echo "[debug:e2e] spec: $spec"
echo "[debug:e2e] log: $log"
rc=0
debug_run "$log" "$verbose" -- bash "$repo_root/app/scripts/e2e-run-spec.sh" "$spec" "$suffix" || rc=$?
if [ "$verbose" != "1" ]; then
debug_summarize_wdio "$log"
fi
if [ "$rc" != "0" ]; then
echo
echo "[debug:e2e] FAILED (exit $rc) — full log: $log"
else
echo "[debug:e2e] OK — log: $log"
fi
exit "$rc"
+83
View File
@@ -0,0 +1,83 @@
#!/usr/bin/env bash
# Shared helpers for scripts/debug/*.sh. Source; do not execute.
set -euo pipefail
debug_repo_root() {
(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
}
debug_log_dir() {
local root
root="$(debug_repo_root)"
mkdir -p "$root/target/debug-logs"
echo "$root/target/debug-logs"
}
debug_timestamp() {
date +%Y%m%d-%H%M%S
}
# Run a command, tee its combined output to a log file, return its exit code.
# Usage: debug_run <log_file> <verbose:0|1> -- <cmd> [args…]
debug_run() {
local log="$1"; shift
local verbose="$1"; shift
if [ "${1:-}" = "--" ]; then shift; fi
local rc=0
if [ "$verbose" = "1" ]; then
set +e
"$@" 2>&1 | tee "$log"
rc=${PIPESTATUS[0]}
set -e
else
set +e
"$@" >"$log" 2>&1
rc=$?
set -e
fi
return "$rc"
}
# Print a short summary + the failure block(s) from a Vitest log.
debug_summarize_vitest() {
local log="$1"
echo
echo "--- summary ---"
grep -E '^[[:space:]]*(Test Files|Tests|Duration|Start at)' "$log" | tail -n 20 || true
if grep -qE '^[[:space:]]*FAIL ' "$log"; then
echo
echo "--- failures ---"
grep -E '^[[:space:]]*FAIL ' "$log" || true
echo
echo "--- failure detail (first 200 lines after first FAIL) ---"
awk '/^[[:space:]]*FAIL /{found=1} found{print; n++; if (n>=200) exit}' "$log"
fi
}
# Print summary lines from a WDIO/Mocha run log.
debug_summarize_wdio() {
local log="$1"
echo
echo "--- summary ---"
grep -E '(passing|failing|pending|tests?, )' "$log" | tail -n 10 || true
if grep -qE '^[[:space:]]*[0-9]+\)' "$log"; then
echo
echo "--- failure detail ---"
awk '/^[[:space:]]*[0-9]+\)/{found=1} found{print}' "$log" | head -n 200
fi
}
# Print summary + failure tails from a cargo-test log.
debug_summarize_cargo() {
local log="$1"
echo
echo "--- summary ---"
grep -E '^test result:' "$log" | tail -n 20 || true
if grep -qE '^failures:' "$log"; then
echo
echo "--- failures ---"
awk '/^failures:/{found=1} found{print}' "$log" | head -n 200
fi
}
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env bash
# logs.sh [list|last|<file>] [--head N | --tail N]
set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib.sh
source "$here/lib.sh"
target="${1:-list}"
shift || true
mode=""
lines="200"
while [ $# -gt 0 ]; do
case "$1" in
--head) mode="head"; lines="${2:?--head requires N}"; shift 2 ;;
--head=*) mode="head"; lines="${1#*=}"; shift ;;
--tail) mode="tail"; lines="${2:?--tail requires N}"; shift 2 ;;
--tail=*) mode="tail"; lines="${1#*=}"; shift ;;
*) echo "[debug:logs] unknown arg: $1" >&2; exit 1 ;;
esac
done
log_dir="$(debug_log_dir)"
if [ "$target" = "list" ]; then
ls -1t "$log_dir" 2>/dev/null | head -n 50
exit 0
fi
resolve_log() {
local t="$1"
if [ "$t" = "last" ]; then
ls -1t "$log_dir" 2>/dev/null | head -n 1 | awk -v d="$log_dir" '{print d "/" $0}'
return
fi
if [ -f "$t" ]; then echo "$t"; return; fi
if [ -f "$log_dir/$t" ]; then echo "$log_dir/$t"; return; fi
# Prefix match
local match
match=$(ls -1t "$log_dir" 2>/dev/null | grep -F "$t" | head -n 1 || true)
if [ -n "$match" ]; then echo "$log_dir/$match"; return; fi
echo ""
}
file="$(resolve_log "$target")"
if [ -z "$file" ] || [ ! -f "$file" ]; then
echo "[debug:logs] no log matching: $target" >&2
exit 1
fi
echo "[debug:logs] $file"
case "$mode" in
head) head -n "$lines" "$file" ;;
tail) tail -n "$lines" "$file" ;;
"")
if [ "$(wc -l <"$file")" -gt 400 ]; then
echo "--- log is long; showing last 400 lines (use --head/--tail to override) ---"
tail -n 400 "$file"
else
cat "$file"
fi
;;
esac
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# rust.sh [test-filter] [--verbose] [-- <cargo-test-args>…]
# Wraps scripts/test-rust-with-mock.sh.
set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib.sh
source "$here/lib.sh"
verbose=0
filter=""
passthrough=()
while [ $# -gt 0 ]; do
case "$1" in
--verbose) verbose=1; shift ;;
--) shift; passthrough+=("$@"); break ;;
-*) passthrough+=("$1"); shift ;;
*)
if [ -z "$filter" ]; then filter="$1"; else passthrough+=("$1"); fi
shift ;;
esac
done
repo_root="$(debug_repo_root)"
log_dir="$(debug_log_dir)"
log="$log_dir/rust-$(debug_timestamp).log"
cmd=(bash "$repo_root/scripts/test-rust-with-mock.sh")
if [ ${#passthrough[@]} -gt 0 ]; then
cmd+=("${passthrough[@]}")
fi
if [ -n "$filter" ]; then
cmd+=("$filter")
fi
echo "[debug:rust] log: $log"
echo "[debug:rust] cmd: ${cmd[*]}"
rc=0
debug_run "$log" "$verbose" -- "${cmd[@]}" || rc=$?
if [ "$verbose" != "1" ]; then
debug_summarize_cargo "$log"
fi
if [ "$rc" != "0" ]; then
echo
echo "[debug:rust] FAILED (exit $rc) — full log: $log"
else
echo "[debug:rust] OK — log: $log"
fi
exit "$rc"
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# unit.sh [pattern] [-t "<name>"] [--watch] [--verbose] [-- <vitest-args>…]
# Wraps `pnpm --filter openhuman-app test:unit`.
set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib.sh
source "$here/lib.sh"
verbose=0
watch=0
pattern=""
test_name=""
passthrough=()
while [ $# -gt 0 ]; do
case "$1" in
--verbose) verbose=1; shift ;;
--watch) watch=1; shift ;;
-t) test_name="${2:?-t requires a value}"; shift 2 ;;
-t=*) test_name="${1#*=}"; shift ;;
--) shift; passthrough+=("$@"); break ;;
-*)
passthrough+=("$1"); shift ;;
*)
if [ -z "$pattern" ]; then pattern="$1"; else passthrough+=("$1"); fi
shift ;;
esac
done
log_dir="$(debug_log_dir)"
log="$log_dir/unit-$(debug_timestamp).log"
repo_root="$(debug_repo_root)"
cd "$repo_root/app"
cmd=(pnpm exec vitest)
if [ "$watch" = "1" ]; then
: # vitest default is watch
else
cmd+=(run)
fi
cmd+=(--config test/vitest.config.ts)
if [ -n "$test_name" ]; then
cmd+=(-t "$test_name")
fi
if [ -n "$pattern" ]; then
cmd+=("$pattern")
fi
if [ ${#passthrough[@]} -gt 0 ]; then
cmd+=("${passthrough[@]}")
fi
echo "[debug:unit] log: $log"
echo "[debug:unit] cmd: ${cmd[*]}"
rc=0
debug_run "$log" "$verbose" -- "${cmd[@]}" || rc=$?
if [ "$verbose" != "1" ]; then
debug_summarize_vitest "$log"
fi
if [ "$rc" != "0" ]; then
echo
echo "[debug:unit] FAILED (exit $rc) — full log: $log"
else
echo "[debug:unit] OK — log: $log"
fi
exit "$rc"