181 lines
5.1 KiB
Bash
181 lines
5.1 KiB
Bash
#!/usr/bin/env bash
|
|
# Guanghu Hybrid Runner · lightweight remote/local execution check
|
|
#
|
|
# Purpose:
|
|
# Run the same non-paid, non-secret checks on a server or local machine.
|
|
# This is the first hybrid execution layer: servers can act as long-running
|
|
# hands, while local machines keep private secrets and visual review outputs.
|
|
#
|
|
# Safety:
|
|
# - Does not print secret values.
|
|
# - Does not call paid model APIs.
|
|
# - Does not commit or push unless --commit-report is explicitly passed.
|
|
#
|
|
# Usage:
|
|
# bash scripts/hybrid-runner/run.sh
|
|
# bash scripts/hybrid-runner/run.sh --skip-pull
|
|
# bash scripts/hybrid-runner/run.sh --commit-report
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
REPORT_DIR="${REPO_ROOT}/outputs/hybrid-runner"
|
|
REPORT_JSON="${REPORT_DIR}/latest.json"
|
|
REPORT_MD="${REPORT_DIR}/latest.md"
|
|
SKIP_PULL=0
|
|
COMMIT_REPORT=0
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--skip-pull) SKIP_PULL=1; shift ;;
|
|
--commit-report) COMMIT_REPORT=1; shift ;;
|
|
*) echo "Unknown argument: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
mkdir -p "$REPORT_DIR"
|
|
|
|
now_utc="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
host="$(hostname 2>/dev/null || echo unknown)"
|
|
os="$(uname -srm 2>/dev/null || echo unknown)"
|
|
branch="$(git -C "$REPO_ROOT" branch --show-current 2>/dev/null || echo unknown)"
|
|
commit="$(git -C "$REPO_ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown)"
|
|
node_bin="${NODE_BIN:-$(command -v node || true)}"
|
|
python_bin="${PYTHON_BIN:-/Users/bingshuolingdianyuanhe/.workbuddy/binaries/python/envs/default/bin/python3}"
|
|
if [[ ! -x "$python_bin" ]]; then
|
|
python_bin="$(command -v python3 || true)"
|
|
fi
|
|
|
|
checks_json=()
|
|
checks_md=()
|
|
fail_count=0
|
|
|
|
add_check() {
|
|
local name="$1"
|
|
local status="$2"
|
|
local detail="$3"
|
|
local detail_json
|
|
local detail_md
|
|
detail_json="$(json_escape "$detail")"
|
|
detail_md="${detail//$'\n'/ }"
|
|
detail_md="${detail_md//|/\\|}"
|
|
checks_json+=("{\"name\":\"${name}\",\"status\":\"${status}\",\"detail\":${detail_json}}")
|
|
checks_md+=("| ${name} | ${status} | ${detail_md} |")
|
|
if [[ "$status" != "PASS" && "$status" != "SKIP" ]]; then
|
|
fail_count=$((fail_count + 1))
|
|
fi
|
|
}
|
|
|
|
json_escape() {
|
|
local text="$1"
|
|
if [[ -n "$node_bin" ]]; then
|
|
printf '%s' "$text" | "$node_bin" -e 'let s=""; process.stdin.setEncoding("utf8"); process.stdin.on("data", d => s += d); process.stdin.on("end", () => process.stdout.write(JSON.stringify(s)));'
|
|
elif [[ -n "$python_bin" && -x "$python_bin" ]]; then
|
|
printf '%s' "$text" | "$python_bin" -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
|
|
else
|
|
printf '"%s"' "$(printf '%s' "$text" | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
|
fi
|
|
}
|
|
|
|
run_check() {
|
|
local name="$1"
|
|
shift
|
|
local out
|
|
local status="PASS"
|
|
set +e
|
|
out="$("$@" 2>&1)"
|
|
local code=$?
|
|
set -e
|
|
if [[ $code -ne 0 ]]; then
|
|
status="FAIL"
|
|
fi
|
|
add_check "$name" "$status" "${out:0:1200}"
|
|
}
|
|
|
|
cd "$REPO_ROOT"
|
|
|
|
if [[ "$SKIP_PULL" -eq 0 ]]; then
|
|
run_check "git pull" git pull --ff-only
|
|
else
|
|
add_check "git pull" "SKIP" "--skip-pull"
|
|
fi
|
|
|
|
if [[ -n "$node_bin" ]]; then
|
|
run_check "node version" "$node_bin" --version
|
|
run_check "video ai js syntax" bash -lc "find video-ai-system/engines video-ai-system/tools -type f \\( -name '*.js' -o -name '*.mjs' \\) | sort | while read f; do \"$node_bin\" --check \"\$f\" >/dev/null || exit 1; done"
|
|
if [[ -f "video-ai-system/tools/audit-system.js" ]]; then
|
|
run_check "video ai audit" "$node_bin" video-ai-system/tools/audit-system.js
|
|
fi
|
|
else
|
|
add_check "node checks" "SKIP" "node not found"
|
|
fi
|
|
|
|
if [[ -n "$python_bin" && -x "$python_bin" ]]; then
|
|
run_check "python version" "$python_bin" --version
|
|
run_check "video ai python syntax" bash -lc "find video-ai-system/engines video-ai-system/tools -type f -name '*.py' | sort | while read f; do \"$python_bin\" -m py_compile \"\$f\" >/dev/null || exit 1; done"
|
|
else
|
|
add_check "python checks" "SKIP" "python not found"
|
|
fi
|
|
|
|
status="PASS"
|
|
if [[ "$fail_count" -gt 0 ]]; then
|
|
status="FAIL"
|
|
fi
|
|
|
|
cat > "$REPORT_JSON" <<EOF
|
|
{
|
|
"generatedAt": "${now_utc}",
|
|
"runner": "guanghu-hybrid-runner-v1",
|
|
"host": "${host}",
|
|
"os": "${os}",
|
|
"repo": {
|
|
"branch": "${branch}",
|
|
"commit": "${commit}"
|
|
},
|
|
"policy": {
|
|
"paidApiCalls": false,
|
|
"secretValuesPrinted": false,
|
|
"localJzaoRequired": false,
|
|
"commitReport": ${COMMIT_REPORT}
|
|
},
|
|
"status": "${status}",
|
|
"failCount": ${fail_count},
|
|
"checks": [
|
|
$(IFS=,; echo "${checks_json[*]}")
|
|
]
|
|
}
|
|
EOF
|
|
|
|
{
|
|
echo "# Guanghu Hybrid Runner Report"
|
|
echo ""
|
|
echo "- generatedAt: ${now_utc}"
|
|
echo "- host: ${host}"
|
|
echo "- os: ${os}"
|
|
echo "- branch: ${branch}"
|
|
echo "- commit: ${commit}"
|
|
echo "- status: ${status}"
|
|
echo "- policy: no paid API calls, no secret values, no JZAO dependency"
|
|
echo ""
|
|
echo "| Check | Status | Detail |"
|
|
echo "|---|---|---|"
|
|
printf '%s\n' "${checks_md[@]}"
|
|
} > "$REPORT_MD"
|
|
|
|
echo "Hybrid runner status: ${status}"
|
|
echo "Report: ${REPORT_MD}"
|
|
|
|
if [[ "$COMMIT_REPORT" -eq 1 ]]; then
|
|
git add -f "$REPORT_JSON" "$REPORT_MD"
|
|
if git diff --cached --quiet; then
|
|
echo "No report changes to commit."
|
|
else
|
|
git commit -m "chore: update hybrid runner report"
|
|
git push origin "$branch"
|
|
fi
|
|
fi
|
|
|
|
if [[ "$status" != "PASS" ]]; then
|
|
exit 1
|
|
fi
|