Compare commits
2 Commits
18f559c4e6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc17432975 | ||
|
|
48e30b9d0e |
27
Dockerfile
27
Dockerfile
@@ -35,7 +35,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
strace \
|
strace \
|
||||||
file \
|
file \
|
||||||
less \
|
less \
|
||||||
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
||||||
&& apt-get install -y nodejs \
|
&& apt-get install -y nodejs \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
@@ -99,6 +99,16 @@ RUN mkdir -p /data /data/.cache/pip /data/.cache/npm /data/.local && \
|
|||||||
# Set working directory to the persistent volume
|
# Set working directory to the persistent volume
|
||||||
WORKDIR /data
|
WORKDIR /data
|
||||||
|
|
||||||
|
# Install startup and OpenClaw node helper scripts
|
||||||
|
COPY scripts/clawdbox-entrypoint /usr/local/bin/clawdbox-entrypoint
|
||||||
|
COPY scripts/start-clawdbox-node /usr/local/bin/start-clawdbox-node
|
||||||
|
COPY scripts/status-clawdbox-node /usr/local/bin/status-clawdbox-node
|
||||||
|
COPY scripts/stop-clawdbox-node /usr/local/bin/stop-clawdbox-node
|
||||||
|
RUN chmod +x /usr/local/bin/clawdbox-entrypoint \
|
||||||
|
/usr/local/bin/start-clawdbox-node \
|
||||||
|
/usr/local/bin/status-clawdbox-node \
|
||||||
|
/usr/local/bin/stop-clawdbox-node
|
||||||
|
|
||||||
# Expose SSH port (non-privileged)
|
# Expose SSH port (non-privileged)
|
||||||
EXPOSE 2222
|
EXPOSE 2222
|
||||||
|
|
||||||
@@ -119,16 +129,5 @@ RUN echo 'export PS1="\[\e[32m\]\u@clawdbox\[\e[m\]:\[\e[34m\]\w\[\e[m\]\$ "' >>
|
|||||||
echo 'export HISTSIZE=10000' >> /home/claw/.bashrc && \
|
echo 'export HISTSIZE=10000' >> /home/claw/.bashrc && \
|
||||||
echo 'export HISTFILESIZE=10000' >> /home/claw/.bashrc
|
echo 'export HISTFILESIZE=10000' >> /home/claw/.bashrc
|
||||||
|
|
||||||
# Start SSH daemon
|
# Start SSH in the foreground and opportunistically start the OpenClaw node host.
|
||||||
# The keys are generated if they don't exist on the persistent volume
|
CMD ["/usr/local/bin/clawdbox-entrypoint"]
|
||||||
CMD ["/bin/bash", "-c", "\
|
|
||||||
mkdir -p /data/ssh && \
|
|
||||||
for keytype in rsa ecdsa ed25519; do \
|
|
||||||
if [ ! -f /data/ssh/ssh_host_${keytype}_key ]; then \
|
|
||||||
echo \"Generating persistent host ${keytype} key...\"; \
|
|
||||||
ssh-keygen -q -f /data/ssh/ssh_host_${keytype}_key -N '' -t ${keytype}; \
|
|
||||||
fi; \
|
|
||||||
done && \
|
|
||||||
chmod 600 /data/ssh/ssh_host_*_key && \
|
|
||||||
ln -sf /data/.gitconfig ~/.gitconfig && \
|
|
||||||
/usr/sbin/sshd -D -e -f /etc/ssh/sshd_config"]
|
|
||||||
|
|||||||
45
README.md
45
README.md
@@ -11,13 +11,14 @@ This container provides a stable, tool-rich environment for the AI agent to:
|
|||||||
|
|
||||||
## Tools Included
|
## Tools Included
|
||||||
- **Core:** curl, wget, git, jq, yq, unzip, tar, vim/nano, tree, less
|
- **Core:** curl, wget, git, jq, yq, unzip, tar, vim/nano, tree, less
|
||||||
- **Dev:** python3 (pip/venv), build-essential, nodejs (v20), npm
|
- **Dev:** python3 (pip/venv), build-essential, nodejs (v22), npm
|
||||||
- **Python Libraries:** httpie, pyyaml, requests, black, ipython
|
- **Python Libraries:** httpie, pyyaml, requests, black, ipython
|
||||||
- **Network:** ping, dnsutils, net-tools, openssh-server/client, sshpass
|
- **Network:** ping, dnsutils, net-tools, openssh-server/client, sshpass
|
||||||
- **Media:** ffmpeg
|
- **Media:** ffmpeg
|
||||||
- **Monitoring:** htop, tmux, ncdu, strace
|
- **Monitoring:** htop, tmux, ncdu, strace
|
||||||
- **Kubernetes:** OpenShift CLI (oc)
|
- **Kubernetes:** OpenShift CLI (oc)
|
||||||
- **Search:** ripgrep (fast grep alternative)
|
- **Search:** ripgrep (fast grep alternative)
|
||||||
|
- **Agent node:** self-starting OpenClaw node host helper for `ClawdBox-CLI`
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -76,6 +77,14 @@ The `/data` volume preserves data across container restarts:
|
|||||||
```
|
```
|
||||||
/data/
|
/data/
|
||||||
├── ssh/ # SSH host keys (auto-generated on first run)
|
├── ssh/ # SSH host keys (auto-generated on first run)
|
||||||
|
├── agents/
|
||||||
|
│ └── clawd/ # Durable OpenClaw agent workspace and node host
|
||||||
|
│ ├── bin/ # start/status/stop helpers and openclaw symlink
|
||||||
|
│ ├── logs/ # node-host logs and pid file
|
||||||
|
│ ├── notes/ # operator notes
|
||||||
|
│ ├── src/ # source checkouts and experiments
|
||||||
|
│ ├── tmp/ # scratch files
|
||||||
|
│ └── tools/ # persistent tool installs
|
||||||
├── scripts/ # Helper scripts (from ConfigMap, read-only)
|
├── scripts/ # Helper scripts (from ConfigMap, read-only)
|
||||||
│ ├── disk-usage.sh
|
│ ├── disk-usage.sh
|
||||||
│ ├── health-check.sh
|
│ ├── health-check.sh
|
||||||
@@ -92,6 +101,40 @@ The `/data` volume preserves data across container restarts:
|
|||||||
|
|
||||||
**Storage:** 10Gi PersistentVolumeClaim (ReadWriteOnce)
|
**Storage:** 10Gi PersistentVolumeClaim (ReadWriteOnce)
|
||||||
|
|
||||||
|
## OpenClaw Node Host
|
||||||
|
|
||||||
|
ClawdBox runs SSH and the `ClawdBox-CLI` node host as separate containers in
|
||||||
|
the same pod. Kubernetes supervises the node container, while its identity,
|
||||||
|
runtime configuration, and exec approvals persist under
|
||||||
|
`/data/agents/clawd/node-home`.
|
||||||
|
|
||||||
|
The helper scripts are copied into `/data/agents/clawd/bin/` on each startup:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
start-clawdbox-node
|
||||||
|
status-clawdbox-node
|
||||||
|
stop-clawdbox-node
|
||||||
|
```
|
||||||
|
|
||||||
|
The node host installs `openclaw@2026.7.2-beta.3` under
|
||||||
|
`/data/agents/clawd/tools/openclaw-node` if it is missing or stale. It gets the
|
||||||
|
Gateway token from `OPENCLAW_GATEWAY_TOKEN` when set, otherwise from the live
|
||||||
|
`openclaw` deployment via the mounted kubeconfig.
|
||||||
|
|
||||||
|
Useful overrides:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
OPENCLAW_VERSION=2026.7.2-beta.3
|
||||||
|
OPENCLAW_GATEWAY_HOST=openclaw.apps.lab.apilab.us
|
||||||
|
OPENCLAW_GATEWAY_PORT=443
|
||||||
|
OPENCLAW_GATEWAY_TLS=true
|
||||||
|
CLAWDBOX_NODE_DISPLAY_NAME=ClawdBox-CLI
|
||||||
|
CLAWDBOX_NODE_HOME=/data/agents/clawd/node-home
|
||||||
|
```
|
||||||
|
|
||||||
|
If node startup fails, SSH remains available while Kubernetes restarts the
|
||||||
|
node container. Check `/data/agents/clawd/logs/node-host.log` for details.
|
||||||
|
|
||||||
## Common Tasks
|
## Common Tasks
|
||||||
|
|
||||||
### Quick Operations (Using Makefile)
|
### Quick Operations (Using Makefile)
|
||||||
|
|||||||
@@ -41,6 +41,16 @@ data:
|
|||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
echo "=== OpenClaw Node Host ==="
|
||||||
|
if command -v status-clawdbox-node > /dev/null 2>&1; then
|
||||||
|
status-clawdbox-node
|
||||||
|
elif [ -x /data/agents/clawd/bin/status-clawdbox-node ]; then
|
||||||
|
/data/agents/clawd/bin/status-clawdbox-node
|
||||||
|
else
|
||||||
|
echo "status-clawdbox-node helper not found"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
echo "=== Disk Space ==="
|
echo "=== Disk Space ==="
|
||||||
df -h /data
|
df -h /data
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -58,6 +58,18 @@ spec:
|
|||||||
value: noninteractive
|
value: noninteractive
|
||||||
- name: TZ
|
- name: TZ
|
||||||
value: UTC
|
value: UTC
|
||||||
|
- name: CLAWDBOX_START_NODE
|
||||||
|
value: "false"
|
||||||
|
- name: OPENCLAW_VERSION
|
||||||
|
value: "2026.7.2-beta.3"
|
||||||
|
- name: OPENCLAW_GATEWAY_HOST
|
||||||
|
value: openclaw.apps.lab.apilab.us
|
||||||
|
- name: OPENCLAW_GATEWAY_PORT
|
||||||
|
value: "443"
|
||||||
|
- name: OPENCLAW_GATEWAY_TLS
|
||||||
|
value: "true"
|
||||||
|
- name: CLAWDBOX_NODE_DISPLAY_NAME
|
||||||
|
value: ClawdBox-CLI
|
||||||
startupProbe:
|
startupProbe:
|
||||||
tcpSocket:
|
tcpSocket:
|
||||||
port: ssh
|
port: ssh
|
||||||
@@ -100,6 +112,56 @@ spec:
|
|||||||
capabilities:
|
capabilities:
|
||||||
drop: ["ALL"]
|
drop: ["ALL"]
|
||||||
add: ["NET_BIND_SERVICE"]
|
add: ["NET_BIND_SERVICE"]
|
||||||
|
- name: openclaw-node
|
||||||
|
image: default-route-openshift-image-registry.apps.lab.apilab.us/clawdbox/clawdbox:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -lc
|
||||||
|
- |
|
||||||
|
set -eu
|
||||||
|
/usr/local/bin/start-clawdbox-node
|
||||||
|
PID=$(cat /data/agents/clawd/logs/node-host.pid)
|
||||||
|
while kill -0 "$PID"; do
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
env:
|
||||||
|
- name: HOME
|
||||||
|
value: /data/agents/clawd/node-home
|
||||||
|
- name: OPENCLAW_STATE_DIR
|
||||||
|
value: /data/agents/clawd/node-home/.openclaw
|
||||||
|
- name: KUBECONFIG
|
||||||
|
value: /home/claw/.kube/config
|
||||||
|
- name: OPENCLAW_VERSION
|
||||||
|
value: "2026.7.2-beta.3"
|
||||||
|
- name: OPENCLAW_GATEWAY_HOST
|
||||||
|
value: openclaw.apps.lab.apilab.us
|
||||||
|
- name: OPENCLAW_GATEWAY_PORT
|
||||||
|
value: "443"
|
||||||
|
- name: OPENCLAW_GATEWAY_TLS
|
||||||
|
value: "true"
|
||||||
|
- name: CLAWDBOX_NODE_DISPLAY_NAME
|
||||||
|
value: ClawdBox-CLI
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /data
|
||||||
|
name: data-volume
|
||||||
|
- mountPath: /home/claw/.kube
|
||||||
|
name: kubeconfig-secret
|
||||||
|
readOnly: true
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: "768Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
volumes:
|
volumes:
|
||||||
- name: data-volume
|
- name: data-volume
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
|
|||||||
46
scripts/clawdbox-entrypoint
Normal file
46
scripts/clawdbox-entrypoint
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=/data/agents/clawd
|
||||||
|
|
||||||
|
mkdir -p /data/ssh /data/.cache/pip /data/.cache/npm /data/.local
|
||||||
|
mkdir -p "$ROOT/bin" "$ROOT/src" "$ROOT/tmp" "$ROOT/logs" "$ROOT/notes" "$ROOT/tools"
|
||||||
|
|
||||||
|
for keytype in rsa ecdsa ed25519; do
|
||||||
|
if [ ! -f "/data/ssh/ssh_host_${keytype}_key" ]; then
|
||||||
|
echo "Generating persistent host ${keytype} key..."
|
||||||
|
ssh-keygen -q -f "/data/ssh/ssh_host_${keytype}_key" -N '' -t "$keytype"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
chmod 600 /data/ssh/ssh_host_*_key
|
||||||
|
|
||||||
|
if [ -f /data/.gitconfig ]; then
|
||||||
|
ln -sf /data/.gitconfig "$HOME/.gitconfig"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "$ROOT/README.md" <<'EOF'
|
||||||
|
# ClawdBox Agent Workspace
|
||||||
|
|
||||||
|
Durable agent workspace for OpenClaw work that should survive pod restarts.
|
||||||
|
|
||||||
|
- `bin/` helper commands
|
||||||
|
- `src/` source checkouts and experiments
|
||||||
|
- `tmp/` scratch files
|
||||||
|
- `logs/` process logs
|
||||||
|
- `notes/` operator notes
|
||||||
|
- `tools/` persistent tool installs
|
||||||
|
EOF
|
||||||
|
|
||||||
|
for script in start-clawdbox-node status-clawdbox-node stop-clawdbox-node; do
|
||||||
|
cp "/usr/local/bin/${script}" "$ROOT/bin/${script}"
|
||||||
|
done
|
||||||
|
|
||||||
|
export PATH="$ROOT/bin:/usr/local/bin:$PATH"
|
||||||
|
|
||||||
|
if [ "${CLAWDBOX_START_NODE:-true}" = "true" ]; then
|
||||||
|
start-clawdbox-node || {
|
||||||
|
echo "ClawdBox-CLI node host did not start; SSH will remain available." >&2
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec /usr/sbin/sshd -D -e -f /etc/ssh/sshd_config
|
||||||
89
scripts/start-clawdbox-node
Normal file
89
scripts/start-clawdbox-node
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT=${CLAWDBOX_AGENT_ROOT:-/data/agents/clawd}
|
||||||
|
LOG_DIR="$ROOT/logs"
|
||||||
|
PID_FILE="$LOG_DIR/node-host.pid"
|
||||||
|
LOG_FILE="$LOG_DIR/node-host.log"
|
||||||
|
OPENCLAW_DIR="$ROOT/tools/openclaw-node"
|
||||||
|
OPENCLAW_VERSION=${OPENCLAW_VERSION:-2026.7.2-beta.3}
|
||||||
|
DISPLAY_NAME=${CLAWDBOX_NODE_DISPLAY_NAME:-ClawdBox-CLI}
|
||||||
|
GATEWAY_HOST=${OPENCLAW_GATEWAY_HOST:-openclaw.apps.lab.apilab.us}
|
||||||
|
GATEWAY_PORT=${OPENCLAW_GATEWAY_PORT:-443}
|
||||||
|
NODE_HOME=${CLAWDBOX_NODE_HOME:-$ROOT/node-home}
|
||||||
|
|
||||||
|
export HOME="$NODE_HOME"
|
||||||
|
export OPENCLAW_STATE_DIR=${OPENCLAW_STATE_DIR:-$NODE_HOME/.openclaw}
|
||||||
|
export KUBECONFIG=${KUBECONFIG:-/home/claw/.kube/config}
|
||||||
|
|
||||||
|
mkdir -p "$ROOT/bin" "$ROOT/tools" "$LOG_DIR" "$OPENCLAW_DIR" "$HOME" "$OPENCLAW_STATE_DIR"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '%s %s\n' "$(date -Iseconds)" "$*" | tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
old=$(cat "$PID_FILE" 2>/dev/null || true)
|
||||||
|
case "$old" in
|
||||||
|
*[!0-9]*|"") ;;
|
||||||
|
*)
|
||||||
|
if kill -0 "$old" 2>/dev/null; then
|
||||||
|
echo "$DISPLAY_NAME already running: pid $old"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$OPENCLAW_DIR/package.json" ]; then
|
||||||
|
cat > "$OPENCLAW_DIR/package.json" <<EOF
|
||||||
|
{
|
||||||
|
"name": "clawdbox-openclaw-node",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"openclaw": "$OPENCLAW_VERSION"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
installed_version=""
|
||||||
|
if [ -f "$OPENCLAW_DIR/node_modules/openclaw/package.json" ]; then
|
||||||
|
installed_version=$(node -p "require('$OPENCLAW_DIR/node_modules/openclaw/package.json').version" 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$installed_version" != "$OPENCLAW_VERSION" ]; then
|
||||||
|
log "Installing openclaw@$OPENCLAW_VERSION under $OPENCLAW_DIR"
|
||||||
|
npm install --prefix "$OPENCLAW_DIR" "openclaw@$OPENCLAW_VERSION" --omit=dev >> "$LOG_FILE" 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
OPENCLAW_BIN="$OPENCLAW_DIR/node_modules/.bin/openclaw"
|
||||||
|
if [ ! -x "$OPENCLAW_BIN" ]; then
|
||||||
|
log "OpenClaw binary not found at $OPENCLAW_BIN"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ln -sf "$OPENCLAW_BIN" "$ROOT/bin/openclaw"
|
||||||
|
|
||||||
|
TOKEN=${OPENCLAW_GATEWAY_TOKEN:-}
|
||||||
|
if [ -z "$TOKEN" ]; then
|
||||||
|
TOKEN=$(oc get deployment openclaw -n openclaw -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="OPENCLAW_GATEWAY_TOKEN")].value}' 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
if [ -z "$TOKEN" ]; then
|
||||||
|
log "OPENCLAW_GATEWAY_TOKEN is unavailable; skipping node-host startup"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TLS_FLAG=""
|
||||||
|
if [ "${OPENCLAW_GATEWAY_TLS:-true}" = "true" ]; then
|
||||||
|
TLS_FLAG="--tls"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Starting $DISPLAY_NAME against $GATEWAY_HOST:$GATEWAY_PORT"
|
||||||
|
OPENCLAW_GATEWAY_TOKEN="$TOKEN" nohup "$OPENCLAW_BIN" node run \
|
||||||
|
--display-name "$DISPLAY_NAME" \
|
||||||
|
--host "$GATEWAY_HOST" \
|
||||||
|
--port "$GATEWAY_PORT" \
|
||||||
|
$TLS_FLAG >> "$LOG_FILE" 2>&1 &
|
||||||
|
echo $! > "$PID_FILE"
|
||||||
|
sleep 1
|
||||||
|
echo "Started $DISPLAY_NAME node host: pid $(cat "$PID_FILE")"
|
||||||
18
scripts/status-clawdbox-node
Normal file
18
scripts/status-clawdbox-node
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT=${CLAWDBOX_AGENT_ROOT:-/data/agents/clawd}
|
||||||
|
PID_FILE="$ROOT/logs/node-host.pid"
|
||||||
|
LOG_FILE="$ROOT/logs/node-host.log"
|
||||||
|
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
pid=$(cat "$PID_FILE" 2>/dev/null || true)
|
||||||
|
case "$pid" in
|
||||||
|
*[!0-9]*|"") echo "Invalid pid file: $pid" ;;
|
||||||
|
*) ps -p "$pid" -o pid,etime,cmd || true ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
echo "No pid file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -n '1,120p' "$LOG_FILE" 2>/dev/null || true
|
||||||
23
scripts/stop-clawdbox-node
Normal file
23
scripts/stop-clawdbox-node
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT=${CLAWDBOX_AGENT_ROOT:-/data/agents/clawd}
|
||||||
|
PID_FILE="$ROOT/logs/node-host.pid"
|
||||||
|
|
||||||
|
if [ ! -f "$PID_FILE" ]; then
|
||||||
|
echo "No pid file"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
pid=$(cat "$PID_FILE" 2>/dev/null || true)
|
||||||
|
case "$pid" in
|
||||||
|
*[!0-9]*|"")
|
||||||
|
echo "Invalid pid file: $pid"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
kill "$pid" 2>/dev/null || true
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
echo "Stopped ClawdBox-CLI node host: pid $pid"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user