@ssdavidai/zoclaw 1.2.1 → 1.3.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/bootstrap.sh +120 -18
- package/scripts/setup.sh +14 -7
package/package.json
CHANGED
package/scripts/bootstrap.sh
CHANGED
|
@@ -3,19 +3,25 @@
|
|
|
3
3
|
# Run AFTER: zotail is configured + `openclaw configure` has been run.
|
|
4
4
|
# Patches the default openclaw config so the gateway is reachable
|
|
5
5
|
# via Tailscale Serve (both TUI and Control UI in browser).
|
|
6
|
+
# Also migrates secrets to Zo secrets and registers gateway as a
|
|
7
|
+
# Zo user service (supervisord).
|
|
6
8
|
set -euo pipefail
|
|
7
9
|
|
|
8
10
|
CONFIG="${HOME}/.openclaw/openclaw.json"
|
|
11
|
+
SECRETS_FILE="/root/.zo_secrets"
|
|
12
|
+
USER_SUPERVISOR="/etc/zo/supervisord-user.conf"
|
|
9
13
|
|
|
10
14
|
if [ ! -f "$CONFIG" ]; then
|
|
11
15
|
echo "Error: $CONFIG not found. Run 'openclaw configure' first."
|
|
12
16
|
exit 1
|
|
13
17
|
fi
|
|
14
18
|
|
|
19
|
+
# ─── 1. Patch openclaw config ─────────────────────────────────────────
|
|
20
|
+
|
|
15
21
|
echo "Patching openclaw config for Tailscale Serve..."
|
|
16
22
|
|
|
17
23
|
# Patch gateway config — use OpenClaw's native tailscale integration.
|
|
18
|
-
#
|
|
24
|
+
# Also sets workspace to /home/workspace/.
|
|
19
25
|
node -e "
|
|
20
26
|
const fs = require('fs');
|
|
21
27
|
const cfg = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
|
|
@@ -49,6 +55,11 @@ node -e "
|
|
|
49
55
|
// names that don't match real command IDs, triggering audit warnings)
|
|
50
56
|
if (gw.nodes?.denyCommands) delete gw.nodes.denyCommands;
|
|
51
57
|
|
|
58
|
+
// Set workspace to /home/workspace/ (Zo standard workspace)
|
|
59
|
+
cfg.agents ??= {};
|
|
60
|
+
cfg.agents.defaults ??= {};
|
|
61
|
+
cfg.agents.defaults.workspace = '/home/workspace/';
|
|
62
|
+
|
|
52
63
|
// Fix credentials dir permissions (create if missing)
|
|
53
64
|
const credDir = process.env.HOME + '/.openclaw/credentials';
|
|
54
65
|
if (!fs.existsSync(credDir)) fs.mkdirSync(credDir, { recursive: true, mode: 0o700 });
|
|
@@ -62,40 +73,131 @@ echo " gateway.tailscale.mode = serve"
|
|
|
62
73
|
echo " gateway.trustedProxies = [127.0.0.1/32]"
|
|
63
74
|
echo " gateway.auth.allowTailscale = true"
|
|
64
75
|
echo " gateway.controlUi.enabled = true"
|
|
76
|
+
echo " agents.defaults.workspace = /home/workspace/"
|
|
65
77
|
echo " nodes.denyCommands -> removed"
|
|
66
78
|
echo " credentials dir -> 700"
|
|
67
79
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
# ─── 2. Migrate secrets to Zo secrets ─────────────────────────────────
|
|
81
|
+
|
|
82
|
+
echo ""
|
|
83
|
+
echo "Migrating secrets to Zo secrets..."
|
|
84
|
+
|
|
85
|
+
# Extract gateway token from openclaw config
|
|
86
|
+
GW_TOKEN=$(node -pe "JSON.parse(require('fs').readFileSync('${CONFIG}','utf8')).gateway?.auth?.token ?? ''" 2>/dev/null || true)
|
|
87
|
+
|
|
88
|
+
# Extract OpenRouter API key from agent auth profiles
|
|
89
|
+
AGENT_AUTH="${HOME}/.openclaw/agents/main/agent/auth-profiles.json"
|
|
90
|
+
OR_KEY=""
|
|
91
|
+
if [ -f "$AGENT_AUTH" ]; then
|
|
92
|
+
OR_KEY=$(node -pe "
|
|
93
|
+
const p = JSON.parse(require('fs').readFileSync('${AGENT_AUTH}','utf8'));
|
|
94
|
+
const k = Object.values(p.profiles || {}).find(v => v.provider === 'openrouter');
|
|
95
|
+
k?.key ?? ''
|
|
96
|
+
" 2>/dev/null || true)
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# Helper: add or update a key in zo_secrets
|
|
100
|
+
upsert_secret() {
|
|
101
|
+
local key="$1" val="$2"
|
|
102
|
+
if [ -z "$val" ]; then return; fi
|
|
103
|
+
if grep -q "^export ${key}=" "$SECRETS_FILE" 2>/dev/null; then
|
|
104
|
+
sed -i "s|^export ${key}=.*|export ${key}=\"${val}\"|" "$SECRETS_FILE"
|
|
105
|
+
echo " ${key} -> updated"
|
|
106
|
+
else
|
|
107
|
+
echo "export ${key}=\"${val}\"" >> "$SECRETS_FILE"
|
|
108
|
+
echo " ${key} -> added"
|
|
109
|
+
fi
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if [ -n "$GW_TOKEN" ]; then
|
|
113
|
+
upsert_secret "OPENCLAW_GATEWAY_TOKEN" "$GW_TOKEN"
|
|
114
|
+
else
|
|
115
|
+
echo " Warning: no gateway token found in config"
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
if [ -n "$OR_KEY" ]; then
|
|
119
|
+
upsert_secret "OPENROUTER_API_KEY" "$OR_KEY"
|
|
120
|
+
else
|
|
121
|
+
echo " No OpenRouter API key found (skipping)"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# Source the updated secrets so they're available for the gateway
|
|
125
|
+
source "$SECRETS_FILE" 2>/dev/null || true
|
|
126
|
+
|
|
127
|
+
# ─── 3. Register gateway as Zo user service ───────────────────────────
|
|
128
|
+
|
|
129
|
+
echo ""
|
|
130
|
+
echo "Registering gateway as Zo user service..."
|
|
131
|
+
|
|
132
|
+
# Kill any existing background gateway process (from previous installs)
|
|
133
|
+
pkill -f "openclaw gateway run" 2>/dev/null || true
|
|
134
|
+
pkill -f "openclaw-gateway" 2>/dev/null || true
|
|
135
|
+
sleep 1
|
|
136
|
+
|
|
137
|
+
# Add [program:openclaw-gateway] to user supervisor config if not present
|
|
138
|
+
if ! grep -q "\[program:openclaw-gateway\]" "$USER_SUPERVISOR" 2>/dev/null; then
|
|
139
|
+
cat >> "$USER_SUPERVISOR" << 'SUPERVISOR'
|
|
140
|
+
[program:openclaw-gateway]
|
|
141
|
+
command=bash -c 'source ~/.zo_secrets 2>/dev/null; exec openclaw gateway run'
|
|
142
|
+
directory=/home/workspace
|
|
143
|
+
autostart=true
|
|
144
|
+
autorestart=true
|
|
145
|
+
startretries=10
|
|
146
|
+
startsecs=5
|
|
147
|
+
stdout_logfile=/dev/shm/openclaw-gateway.log
|
|
148
|
+
stderr_logfile=/dev/shm/openclaw-gateway_err.log
|
|
149
|
+
stdout_logfile_maxbytes=10MB
|
|
150
|
+
stdout_logfile_backups=3
|
|
151
|
+
stopwaitsecs=10
|
|
152
|
+
stopsignal=TERM
|
|
153
|
+
stopasgroup=true
|
|
154
|
+
killasgroup=true
|
|
155
|
+
SUPERVISOR
|
|
156
|
+
echo " Added [program:openclaw-gateway] to user supervisor"
|
|
157
|
+
else
|
|
158
|
+
echo " [program:openclaw-gateway] already in user supervisor"
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# Reload supervisor config and start/restart the gateway
|
|
162
|
+
supervisorctl -c "$USER_SUPERVISOR" reread > /dev/null 2>&1 || true
|
|
163
|
+
supervisorctl -c "$USER_SUPERVISOR" update > /dev/null 2>&1 || true
|
|
74
164
|
sleep 2
|
|
75
|
-
|
|
165
|
+
|
|
166
|
+
# Restart to pick up any config changes
|
|
167
|
+
supervisorctl -c "$USER_SUPERVISOR" restart openclaw-gateway > /dev/null 2>&1 || \
|
|
168
|
+
supervisorctl -c "$USER_SUPERVISOR" start openclaw-gateway > /dev/null 2>&1 || true
|
|
76
169
|
sleep 5
|
|
77
170
|
|
|
78
|
-
|
|
79
|
-
|
|
171
|
+
# Verify gateway is running
|
|
172
|
+
if supervisorctl -c "$USER_SUPERVISOR" status openclaw-gateway 2>/dev/null | grep -q RUNNING; then
|
|
173
|
+
echo " Gateway running (supervised)"
|
|
174
|
+
elif pgrep -f "openclaw-gateway" > /dev/null 2>&1; then
|
|
175
|
+
echo " Gateway running"
|
|
176
|
+
else
|
|
177
|
+
echo " Warning: gateway is not running. Check: supervisorctl -c $USER_SUPERVISOR status"
|
|
178
|
+
echo " Logs: /dev/shm/openclaw-gateway.log"
|
|
80
179
|
exit 1
|
|
81
180
|
fi
|
|
82
181
|
|
|
83
|
-
#
|
|
84
|
-
|
|
182
|
+
# ─── 4. Print access info ─────────────────────────────────────────────
|
|
183
|
+
|
|
85
184
|
TS_HOSTNAME=$(tailscale status --json 2>/dev/null | node -pe "
|
|
86
185
|
const s = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
|
|
87
|
-
(s.Self.DNSName || '').replace(
|
|
186
|
+
(s.Self.DNSName || '').replace(/\\\.\$/, '')
|
|
88
187
|
" 2>/dev/null || true)
|
|
89
188
|
|
|
90
189
|
echo ""
|
|
91
190
|
echo "Ready!"
|
|
92
191
|
echo " TUI: openclaw tui"
|
|
192
|
+
echo " Manage: supervisorctl -c $USER_SUPERVISOR restart openclaw-gateway"
|
|
93
193
|
if [ -n "$TS_HOSTNAME" ]; then
|
|
94
194
|
echo " Browser: https://${TS_HOSTNAME}/"
|
|
95
|
-
if [ -n "$TOKEN" ]; then
|
|
96
|
-
echo " (with token: https://${TS_HOSTNAME}/#token=${TOKEN})"
|
|
97
|
-
fi
|
|
98
195
|
echo ""
|
|
99
|
-
echo "
|
|
100
|
-
echo "
|
|
196
|
+
echo " To access from another device on your tailnet:"
|
|
197
|
+
echo " 1. Open the URL above in your browser"
|
|
198
|
+
echo " 2. Run: openclaw devices list"
|
|
199
|
+
echo " 3. Run: openclaw devices approve <request-id>"
|
|
200
|
+
echo " 4. Refresh the browser"
|
|
201
|
+
echo ""
|
|
202
|
+
echo " This is a one-time pairing per browser."
|
|
101
203
|
fi
|
package/scripts/setup.sh
CHANGED
|
@@ -6,6 +6,7 @@ set -euo pipefail
|
|
|
6
6
|
SECRETS_FILE="${HOME}/.zo_secrets"
|
|
7
7
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
8
|
BOOTSTRAP="${SCRIPT_DIR}/bootstrap.sh"
|
|
9
|
+
USER_SUPERVISOR="/etc/zo/supervisord-user.conf"
|
|
9
10
|
|
|
10
11
|
# ─── Helpers ──────────────────────────────────────────────────────────
|
|
11
12
|
|
|
@@ -75,9 +76,9 @@ else
|
|
|
75
76
|
openclaw onboard --install-daemon
|
|
76
77
|
fi
|
|
77
78
|
|
|
78
|
-
# ─── Step 5: Bootstrap
|
|
79
|
+
# ─── Step 5: Bootstrap (config + secrets + service) ──────────────────
|
|
79
80
|
|
|
80
|
-
step 5 "
|
|
81
|
+
step 5 "Bootstrap"
|
|
81
82
|
|
|
82
83
|
if [ ! -f "$BOOTSTRAP" ]; then
|
|
83
84
|
echo " Error: bootstrap.sh not found at ${BOOTSTRAP}"
|
|
@@ -88,17 +89,23 @@ bash "$BOOTSTRAP"
|
|
|
88
89
|
|
|
89
90
|
# ─── Done ────────────────────────────────────────────────────────────
|
|
90
91
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
TS_HOSTNAME=$(tailscale status --json 2>/dev/null | node -pe "
|
|
93
|
+
const s = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
|
|
94
|
+
(s.Self.DNSName || '').replace(/\\\.\$/, '')
|
|
95
|
+
" 2>/dev/null || true)
|
|
94
96
|
|
|
95
97
|
echo ""
|
|
96
98
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
97
99
|
echo ""
|
|
98
100
|
echo " Setup complete!"
|
|
99
101
|
echo ""
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
echo " Secrets: /root/.zo_secrets"
|
|
103
|
+
echo " Workspace: /home/workspace/"
|
|
104
|
+
echo " Gateway: managed by supervisord (user)"
|
|
105
|
+
echo " Manage: supervisorctl -c $USER_SUPERVISOR restart openclaw-gateway"
|
|
106
|
+
echo ""
|
|
107
|
+
if [ -n "$TS_HOSTNAME" ]; then
|
|
108
|
+
echo " Control UI: https://${TS_HOSTNAME}/"
|
|
102
109
|
echo ""
|
|
103
110
|
echo " (On first browser load, approve device pairing from the CLI:"
|
|
104
111
|
echo " openclaw devices list && openclaw devices approve <id>)"
|