@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ssdavidai/zoclaw",
3
- "version": "1.2.1",
3
+ "version": "1.3.0-next.0",
4
4
  "description": "Set up OpenClaw on Zo with Tailscale access in one command",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -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
- # Ref: https://docs.openclaw.ai/gateway/tailscale
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
- # Restart gateway to pick up config changes.
69
- # The gateway will auto-configure tailscale serve on startup.
70
- # Do NOT use --force as it regenerates the gateway identity
71
- # and invalidates all existing device pairings.
72
- echo "Restarting gateway..."
73
- pkill -f openclaw-gateway 2>/dev/null || true
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
- openclaw gateway run > /dev/null 2>&1 &
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
- if ! pgrep -f openclaw-gateway > /dev/null 2>&1; then
79
- echo "Warning: gateway is not running. Try 'openclaw gateway run' manually."
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
- # Read token and resolve MagicDNS hostname
84
- TOKEN=$(node -pe "JSON.parse(require('fs').readFileSync('${CONFIG}','utf8')).gateway?.auth?.token ?? ''")
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 " Accessible from any device on your tailnet."
100
- echo " Tailscale identity auth is enabled no token needed for tailnet users."
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 Tailscale config ──────────────────────────────
79
+ # ─── Step 5: Bootstrap (config + secrets + service) ──────────────────
79
80
 
80
- step 5 "Tailscale bootstrap"
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
- CONFIG="${HOME}/.openclaw/openclaw.json"
92
- TOKEN=$(node -pe "JSON.parse(require('fs').readFileSync('${CONFIG}','utf8')).gateway?.auth?.token ?? ''" 2>/dev/null || true)
93
- TS_URL=$(tailscale serve status 2>/dev/null | grep -oP 'https://\S+' | head -1 || true)
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
- if [ -n "$TS_URL" ] && [ -n "$TOKEN" ]; then
101
- echo " Control UI: ${TS_URL}?token=${TOKEN}"
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>)"