add zeroclaw local stack follow scripts
This commit is contained in:
@@ -4,13 +4,13 @@ on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "tools/ai/zeroclaw_dual_*.sh"
|
||||
- "tools/ai/zeroclaw_*.sh"
|
||||
- "specs/zeroclaw_dual_hw_*.md"
|
||||
- ".github/workflows/zeroclaw_dual_orchestrator.yml"
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "tools/ai/zeroclaw_dual_*.sh"
|
||||
- "tools/ai/zeroclaw_*.sh"
|
||||
- "specs/zeroclaw_dual_hw_*.md"
|
||||
- ".github/workflows/zeroclaw_dual_orchestrator.yml"
|
||||
workflow_dispatch:
|
||||
@@ -35,6 +35,9 @@ jobs:
|
||||
run: |
|
||||
shellcheck tools/ai/zeroclaw_dual_bootstrap.sh
|
||||
shellcheck tools/ai/zeroclaw_dual_chat.sh
|
||||
shellcheck tools/ai/zeroclaw_stack_up.sh
|
||||
shellcheck tools/ai/zeroclaw_stack_down.sh
|
||||
shellcheck tools/ai/zeroclaw_webhook_send.sh
|
||||
|
||||
- name: Verify spec files
|
||||
run: |
|
||||
|
||||
@@ -66,6 +66,14 @@ This keeps `autonomy.workspace_only = true` effective on a per-repo boundary.
|
||||
- message mode (`-m`) or interactive mode,
|
||||
- provider auto-fallback (`copilot` -> `openai-codex` -> `openrouter`),
|
||||
- token sourcing from `gh auth token` at runtime only when `copilot` is selected.
|
||||
- `tools/ai/zeroclaw_stack_up.sh`
|
||||
- starts local gateway and local follow server,
|
||||
- generates local follow page at `http://127.0.0.1:8788/`,
|
||||
- stores pair token in `artifacts/zeroclaw/pair_token.txt`.
|
||||
- `tools/ai/zeroclaw_stack_down.sh`
|
||||
- stops local gateway/follow processes.
|
||||
- `tools/ai/zeroclaw_webhook_send.sh`
|
||||
- sends one webhook message and appends raw request/response trace to `artifacts/zeroclaw/conversations.jsonl`.
|
||||
|
||||
### 4.3 Provider/cost strategy
|
||||
|
||||
|
||||
@@ -11,10 +11,11 @@ Usage:
|
||||
$(basename "$0") <rtc|zacus|path> -m "message"
|
||||
$(basename "$0") <rtc|zacus|path> --interactive
|
||||
$(basename "$0") <rtc|zacus|path> --hardware
|
||||
$(basename "$0") <rtc|zacus|path> --provider-check
|
||||
USAGE
|
||||
}
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
if [[ $# -lt 1 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
@@ -53,7 +54,7 @@ resolve_provider() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
|
||||
if [[ "${ZEROCLAW_SKIP_COPILOT_CHECK:-0}" != "1" ]] && command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
|
||||
if gh api /user/copilot/billing --silent >/dev/null 2>&1; then
|
||||
local gh_token
|
||||
gh_token="$(gh auth token)"
|
||||
@@ -63,7 +64,12 @@ resolve_provider() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if "$ZEROCLAW_BIN" auth list 2>/dev/null | rg -q "openai-codex:"; then
|
||||
if env -u ZEROCLAW_WORKSPACE "$ZEROCLAW_BIN" auth status 2>/dev/null | rg -q "openai-codex:"; then
|
||||
echo "openai-codex"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if env -u ZEROCLAW_WORKSPACE "$ZEROCLAW_BIN" auth list 2>/dev/null | rg -q "openai-codex:"; then
|
||||
echo "openai-codex"
|
||||
return 0
|
||||
fi
|
||||
@@ -83,10 +89,15 @@ ERR
|
||||
return 1
|
||||
}
|
||||
|
||||
export ZEROCLAW_WORKSPACE="$workspace"
|
||||
provider="$(resolve_provider)"
|
||||
echo "[zeroclaw-dual-chat] workspace=$workspace provider=$provider"
|
||||
|
||||
if [[ "${1:-}" == "--provider-check" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
export ZEROCLAW_WORKSPACE="$workspace"
|
||||
|
||||
if [[ "${1:-}" == "--interactive" ]]; then
|
||||
exec "$ZEROCLAW_BIN" agent -p "$provider"
|
||||
fi
|
||||
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ART_DIR="${ZEROCLAW_ART_DIR:-/Users/cils/Documents/Lelectron_rare/Kill_LIFE/artifacts/zeroclaw}"
|
||||
GW_PID_FILE="$ART_DIR/gateway.pid"
|
||||
FW_PID_FILE="$ART_DIR/follow.pid"
|
||||
|
||||
stop_pid_file() {
|
||||
local pid_file="$1"
|
||||
[[ -f "$pid_file" ]] || return 0
|
||||
local pid
|
||||
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
||||
if [[ -n "$pid" ]] && kill -0 "$pid" >/dev/null 2>&1; then
|
||||
kill "$pid" >/dev/null 2>&1 || true
|
||||
sleep 0.2
|
||||
if kill -0 "$pid" >/dev/null 2>&1; then
|
||||
kill -9 "$pid" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
rm -f "$pid_file"
|
||||
}
|
||||
|
||||
stop_pid_file "$GW_PID_FILE"
|
||||
stop_pid_file "$FW_PID_FILE"
|
||||
echo "ZeroClaw local stack stopped."
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="/Users/cils/Documents/Lelectron_rare/Kill_LIFE"
|
||||
ART_DIR="${ZEROCLAW_ART_DIR:-$ROOT_DIR/artifacts/zeroclaw}"
|
||||
ZEROCLAW_BIN="${ZEROCLAW_BIN:-$ROOT_DIR/zeroclaw/target/release/zeroclaw}"
|
||||
GATEWAY_HOST="${ZEROCLAW_GATEWAY_HOST:-127.0.0.1}"
|
||||
GATEWAY_PORT="${ZEROCLAW_GATEWAY_PORT:-3000}"
|
||||
FOLLOW_PORT="${ZEROCLAW_FOLLOW_PORT:-8788}"
|
||||
|
||||
GW_PID_FILE="$ART_DIR/gateway.pid"
|
||||
FW_PID_FILE="$ART_DIR/follow.pid"
|
||||
GW_LOG="$ART_DIR/gateway.log"
|
||||
FW_LOG="$ART_DIR/follow.log"
|
||||
TOKEN_FILE="$ART_DIR/pair_token.txt"
|
||||
CONVO_FILE="$ART_DIR/conversations.jsonl"
|
||||
INDEX_FILE="$ART_DIR/index.html"
|
||||
|
||||
mkdir -p "$ART_DIR"
|
||||
touch "$CONVO_FILE"
|
||||
|
||||
if [[ ! -x "$ZEROCLAW_BIN" ]]; then
|
||||
if command -v zeroclaw >/dev/null 2>&1; then
|
||||
ZEROCLAW_BIN="$(command -v zeroclaw)"
|
||||
else
|
||||
echo "[fail] zeroclaw binary not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
is_running() {
|
||||
local pid_file="$1"
|
||||
[[ -f "$pid_file" ]] || return 1
|
||||
local pid
|
||||
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
||||
[[ -n "$pid" ]] || return 1
|
||||
kill -0 "$pid" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
if is_running "$GW_PID_FILE"; then
|
||||
echo "[info] gateway already running (pid $(cat "$GW_PID_FILE"))."
|
||||
else
|
||||
nohup "$ZEROCLAW_BIN" gateway --port "$GATEWAY_PORT" --host "$GATEWAY_HOST" >"$GW_LOG" 2>&1 &
|
||||
echo "$!" >"$GW_PID_FILE"
|
||||
fi
|
||||
|
||||
if is_running "$FW_PID_FILE"; then
|
||||
echo "[info] follow server already running (pid $(cat "$FW_PID_FILE"))."
|
||||
else
|
||||
nohup python3 -m http.server "$FOLLOW_PORT" --bind 127.0.0.1 --directory "$ART_DIR" >"$FW_LOG" 2>&1 &
|
||||
echo "$!" >"$FW_PID_FILE"
|
||||
fi
|
||||
|
||||
for _ in $(seq 1 40); do
|
||||
if curl -fsS "http://$GATEWAY_HOST:$GATEWAY_PORT/health" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.25
|
||||
done
|
||||
|
||||
PAIR_CODE="$(grep -Eo 'X-Pairing-Code: [0-9]{6}' "$GW_LOG" 2>/dev/null | tail -1 | awk '{print $2}' || true)"
|
||||
if [[ -n "$PAIR_CODE" ]]; then
|
||||
PAIR_JSON="$(curl -sS -X POST "http://$GATEWAY_HOST:$GATEWAY_PORT/pair" -H "X-Pairing-Code: $PAIR_CODE" || true)"
|
||||
TOKEN="$(printf '%s' "$PAIR_JSON" | python3 -c 'import json,sys
|
||||
raw=sys.stdin.read().strip()
|
||||
try:
|
||||
obj=json.loads(raw) if raw else {}
|
||||
except Exception:
|
||||
obj={}
|
||||
print(obj.get("token",""), end="")')"
|
||||
if [[ -n "$TOKEN" ]]; then
|
||||
printf '%s\n' "$TOKEN" >"$TOKEN_FILE"
|
||||
chmod 600 "$TOKEN_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
cat >"$INDEX_FILE" <<EOF
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="refresh" content="5" />
|
||||
<title>ZeroClaw Local Follow</title>
|
||||
<style>body{font-family:ui-sans-serif,system-ui;margin:20px}code{background:#f4f4f4;padding:2px 4px}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ZeroClaw Local Follow</h1>
|
||||
<ul>
|
||||
<li>Health: <a href="http://$GATEWAY_HOST:$GATEWAY_PORT/health">http://$GATEWAY_HOST:$GATEWAY_PORT/health</a></li>
|
||||
<li>Metrics: <a href="http://$GATEWAY_HOST:$GATEWAY_PORT/metrics">http://$GATEWAY_HOST:$GATEWAY_PORT/metrics</a></li>
|
||||
<li>Gateway log: <a href="/gateway.log">/gateway.log</a></li>
|
||||
<li>Conversation log: <a href="/conversations.jsonl">/conversations.jsonl</a></li>
|
||||
</ul>
|
||||
<p>Follow URL: <code>http://127.0.0.1:$FOLLOW_PORT/</code></p>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
echo "Gateway: http://$GATEWAY_HOST:$GATEWAY_PORT/health"
|
||||
echo "Follow : http://127.0.0.1:$FOLLOW_PORT/"
|
||||
echo "Logs : $GW_LOG"
|
||||
echo "Token : $TOKEN_FILE"
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ART_DIR="${ZEROCLAW_ART_DIR:-/Users/cils/Documents/Lelectron_rare/Kill_LIFE/artifacts/zeroclaw}"
|
||||
HOST="${ZEROCLAW_GATEWAY_HOST:-127.0.0.1}"
|
||||
PORT="${ZEROCLAW_GATEWAY_PORT:-3000}"
|
||||
TOKEN_FILE="$ART_DIR/pair_token.txt"
|
||||
CONVO_FILE="$ART_DIR/conversations.jsonl"
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $(basename "$0") \"message\"" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MESSAGE="$1"
|
||||
TOKEN="${ZEROCLAW_BEARER:-}"
|
||||
if [[ -z "$TOKEN" && -f "$TOKEN_FILE" ]]; then
|
||||
TOKEN="$(cat "$TOKEN_FILE")"
|
||||
fi
|
||||
if [[ -z "$TOKEN" ]]; then
|
||||
echo "[fail] no bearer token found. Start stack first or set ZEROCLAW_BEARER." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
PAYLOAD="$(python3 -c 'import json,sys;print(json.dumps({"message":sys.argv[1]}))' "$MESSAGE")"
|
||||
RESPONSE="$(curl -sS -X POST "http://$HOST:$PORT/webhook" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$PAYLOAD")"
|
||||
|
||||
TS="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
LINE="$(python3 -c 'import json,sys
|
||||
ts,msg,resp=sys.argv[1],sys.argv[2],sys.argv[3]
|
||||
print(json.dumps({"ts":ts,"message":msg,"response_raw":resp},ensure_ascii=False))' "$TS" "$MESSAGE" "$RESPONSE")"
|
||||
printf '%s\n' "$LINE" >>"$CONVO_FILE"
|
||||
|
||||
printf '%s\n' "$RESPONSE"
|
||||
Reference in New Issue
Block a user