@aiassesstech/mighty-mark 0.6.26 → 0.6.28
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/agent/AGENTS.md +32 -0
- package/agent/SOUL.md +23 -0
- package/agent/decisions.md +20 -0
- package/dist/checks/check-runner.d.ts.map +1 -1
- package/dist/checks/check-runner.js +3 -2
- package/dist/checks/check-runner.js.map +1 -1
- package/dist/checks/fleet-communication.d.ts.map +1 -1
- package/dist/checks/fleet-communication.js +2 -0
- package/dist/checks/fleet-communication.js.map +1 -1
- package/dist/cli/check-house.d.ts +53 -0
- package/dist/cli/check-house.d.ts.map +1 -0
- package/dist/cli/check-house.js +203 -0
- package/dist/cli/check-house.js.map +1 -0
- package/dist/cli/runner.d.ts.map +1 -1
- package/dist/cli/runner.js +6 -0
- package/dist/cli/runner.js.map +1 -1
- package/dist/notify/alert-classifier.d.ts +16 -5
- package/dist/notify/alert-classifier.d.ts.map +1 -1
- package/dist/notify/alert-classifier.js +36 -5
- package/dist/notify/alert-classifier.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +50 -0
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
- package/src/scripts/rule-advisory-check.sh +110 -0
- package/src/scripts/snapshot-config.sh +70 -0
- package/src/scripts/upgrade-openclaw.sh +263 -0
- package/src/scripts/validate-openclaw-config.sh +118 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ============================================================================
|
|
3
|
+
# OpenClaw Upgrade Script
|
|
4
|
+
# Author: BB (via Greg)
|
|
5
|
+
# Date: 2026-03-03
|
|
6
|
+
# Purpose: Safely upgrade OpenClaw to latest version with backups and verification
|
|
7
|
+
#
|
|
8
|
+
# This script upgrades the OpenClaw gateway binary only.
|
|
9
|
+
# For plugin/extension upgrades, use the manual sync pattern documented in:
|
|
10
|
+
# .cursor/rules/806-openclaw-extension-upgrade.mdc
|
|
11
|
+
#
|
|
12
|
+
# Mighty Mark monitors OpenClaw version and config integrity as part of
|
|
13
|
+
# the morning health check. After running this script, the next morning
|
|
14
|
+
# report will confirm the upgrade succeeded.
|
|
15
|
+
# ============================================================================
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
GREEN='\033[0;32m'
|
|
20
|
+
YELLOW='\033[1;33m'
|
|
21
|
+
RED='\033[0;31m'
|
|
22
|
+
CYAN='\033[0;36m'
|
|
23
|
+
NC='\033[0m'
|
|
24
|
+
|
|
25
|
+
DRY_RUN=false
|
|
26
|
+
SKIP_GATEWAY_RESTART=false
|
|
27
|
+
|
|
28
|
+
usage() {
|
|
29
|
+
echo "Usage: $0 [OPTIONS]"
|
|
30
|
+
echo ""
|
|
31
|
+
echo "Options:"
|
|
32
|
+
echo " --dry-run Show what would happen without making changes"
|
|
33
|
+
echo " --skip-restart Upgrade binary but don't restart the gateway"
|
|
34
|
+
echo " -h, --help Show this help"
|
|
35
|
+
echo ""
|
|
36
|
+
echo "This script upgrades the OpenClaw gateway binary."
|
|
37
|
+
echo "For plugin upgrades, see .cursor/rules/806-openclaw-extension-upgrade.mdc"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
while [[ $# -gt 0 ]]; do
|
|
41
|
+
case $1 in
|
|
42
|
+
--dry-run) DRY_RUN=true; shift ;;
|
|
43
|
+
--skip-restart) SKIP_GATEWAY_RESTART=true; shift ;;
|
|
44
|
+
-h|--help) usage; exit 0 ;;
|
|
45
|
+
*) echo "Unknown option: $1"; usage; exit 1 ;;
|
|
46
|
+
esac
|
|
47
|
+
done
|
|
48
|
+
|
|
49
|
+
echo -e "${CYAN}════════════════════════════════════════════════════${NC}"
|
|
50
|
+
echo -e "${CYAN} OpenClaw Upgrade Script ${NC}"
|
|
51
|
+
echo -e "${CYAN}════════════════════════════════════════════════════${NC}"
|
|
52
|
+
echo ""
|
|
53
|
+
|
|
54
|
+
if $DRY_RUN; then
|
|
55
|
+
echo -e "${YELLOW} ⚠ DRY RUN — no changes will be made${NC}"
|
|
56
|
+
echo ""
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Step 1: Record current version
|
|
60
|
+
echo -e "${YELLOW}[1/8] Recording current version...${NC}"
|
|
61
|
+
CURRENT_VERSION=$(openclaw --version 2>&1 || echo "unknown")
|
|
62
|
+
echo " Current: $CURRENT_VERSION"
|
|
63
|
+
|
|
64
|
+
LATEST_VERSION=$(npm view openclaw version 2>/dev/null || echo "unknown")
|
|
65
|
+
echo " Latest: $LATEST_VERSION"
|
|
66
|
+
|
|
67
|
+
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ] && [ "$CURRENT_VERSION" != "unknown" ]; then
|
|
68
|
+
echo ""
|
|
69
|
+
echo -e "${GREEN} Already on latest version — nothing to do.${NC}"
|
|
70
|
+
exit 0
|
|
71
|
+
fi
|
|
72
|
+
echo ""
|
|
73
|
+
|
|
74
|
+
# Step 2: Backup config
|
|
75
|
+
echo -e "${YELLOW}[2/8] Backing up configuration...${NC}"
|
|
76
|
+
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
77
|
+
|
|
78
|
+
if [ -f ~/.openclaw/openclaw.json ]; then
|
|
79
|
+
if $DRY_RUN; then
|
|
80
|
+
echo " [DRY RUN] Would backup ~/.openclaw/openclaw.json"
|
|
81
|
+
else
|
|
82
|
+
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.pre-upgrade-$TIMESTAMP
|
|
83
|
+
echo " ✅ ~/.openclaw/openclaw.json → openclaw.json.pre-upgrade-$TIMESTAMP"
|
|
84
|
+
fi
|
|
85
|
+
else
|
|
86
|
+
echo " ⚠️ ~/.openclaw/openclaw.json not found — skipping"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
if [ -f ~/.clawdbot/openclaw.json ]; then
|
|
90
|
+
if $DRY_RUN; then
|
|
91
|
+
echo " [DRY RUN] Would backup ~/.clawdbot/openclaw.json"
|
|
92
|
+
else
|
|
93
|
+
cp ~/.clawdbot/openclaw.json ~/.clawdbot/openclaw.json.pre-upgrade-$TIMESTAMP
|
|
94
|
+
echo " ✅ ~/.clawdbot/openclaw.json → openclaw.json.pre-upgrade-$TIMESTAMP"
|
|
95
|
+
fi
|
|
96
|
+
fi
|
|
97
|
+
echo ""
|
|
98
|
+
|
|
99
|
+
# Step 3: Backup extensions
|
|
100
|
+
echo -e "${YELLOW}[3/8] Backing up extensions...${NC}"
|
|
101
|
+
if [ -d ~/.openclaw/extensions ]; then
|
|
102
|
+
if $DRY_RUN; then
|
|
103
|
+
echo " [DRY RUN] Would backup ~/.openclaw/extensions"
|
|
104
|
+
else
|
|
105
|
+
cp -r ~/.openclaw/extensions ~/.openclaw/extensions.pre-upgrade-$TIMESTAMP
|
|
106
|
+
echo " ✅ ~/.openclaw/extensions → extensions.pre-upgrade-$TIMESTAMP"
|
|
107
|
+
fi
|
|
108
|
+
else
|
|
109
|
+
echo " ⚠️ ~/.openclaw/extensions not found — skipping"
|
|
110
|
+
fi
|
|
111
|
+
echo ""
|
|
112
|
+
|
|
113
|
+
# Step 4: Backup agent workspaces (SOUL.md files etc.)
|
|
114
|
+
echo -e "${YELLOW}[4/8] Backing up agent workspaces...${NC}"
|
|
115
|
+
if [ -d ~/.openclaw/agents ]; then
|
|
116
|
+
if $DRY_RUN; then
|
|
117
|
+
echo " [DRY RUN] Would backup ~/.openclaw/agents"
|
|
118
|
+
else
|
|
119
|
+
cp -r ~/.openclaw/agents ~/.openclaw/agents.pre-upgrade-$TIMESTAMP
|
|
120
|
+
echo " ✅ ~/.openclaw/agents → agents.pre-upgrade-$TIMESTAMP"
|
|
121
|
+
fi
|
|
122
|
+
else
|
|
123
|
+
echo " ⚠️ ~/.openclaw/agents not found — skipping"
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
# Also trigger a fleet backup if the system is installed (pre-upgrade safety net)
|
|
127
|
+
if [ -x /opt/fleet-backup/fleet-backup.sh ]; then
|
|
128
|
+
echo ""
|
|
129
|
+
echo " Fleet backup system detected — running pre-upgrade backup..."
|
|
130
|
+
if $DRY_RUN; then
|
|
131
|
+
echo " [DRY RUN] Would run /opt/fleet-backup/fleet-backup.sh"
|
|
132
|
+
else
|
|
133
|
+
if /opt/fleet-backup/fleet-backup.sh 2>&1 | tail -3; then
|
|
134
|
+
echo " ✅ Fleet backup completed"
|
|
135
|
+
else
|
|
136
|
+
echo -e " ${YELLOW}⚠️ Fleet backup had issues (non-fatal, continuing)${NC}"
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
140
|
+
echo ""
|
|
141
|
+
|
|
142
|
+
# Step 5: Stop gateway
|
|
143
|
+
echo -e "${YELLOW}[5/8] Stopping openclaw-gateway...${NC}"
|
|
144
|
+
if $DRY_RUN; then
|
|
145
|
+
echo " [DRY RUN] Would stop openclaw-gateway"
|
|
146
|
+
elif $SKIP_GATEWAY_RESTART; then
|
|
147
|
+
echo " Skipped (--skip-restart)"
|
|
148
|
+
else
|
|
149
|
+
systemctl stop openclaw-gateway
|
|
150
|
+
sleep 2
|
|
151
|
+
if systemctl is-active --quiet openclaw-gateway; then
|
|
152
|
+
echo -e " ${RED}❌ Gateway still running — aborting${NC}"
|
|
153
|
+
exit 1
|
|
154
|
+
fi
|
|
155
|
+
echo " ✅ Gateway stopped"
|
|
156
|
+
fi
|
|
157
|
+
echo ""
|
|
158
|
+
|
|
159
|
+
# Step 6: Upgrade
|
|
160
|
+
echo -e "${YELLOW}[6/8] Upgrading OpenClaw to latest...${NC}"
|
|
161
|
+
if $DRY_RUN; then
|
|
162
|
+
echo " [DRY RUN] Would run: npm install -g openclaw@latest"
|
|
163
|
+
else
|
|
164
|
+
npm install -g openclaw@latest 2>&1 | tail -5
|
|
165
|
+
fi
|
|
166
|
+
echo ""
|
|
167
|
+
|
|
168
|
+
# Step 7: Start gateway and verify
|
|
169
|
+
echo -e "${YELLOW}[7/8] Starting openclaw-gateway...${NC}"
|
|
170
|
+
if $DRY_RUN; then
|
|
171
|
+
echo " [DRY RUN] Would start openclaw-gateway"
|
|
172
|
+
elif $SKIP_GATEWAY_RESTART; then
|
|
173
|
+
echo " Skipped (--skip-restart)"
|
|
174
|
+
else
|
|
175
|
+
systemctl start openclaw-gateway
|
|
176
|
+
echo " Waiting 10 seconds for startup..."
|
|
177
|
+
sleep 10
|
|
178
|
+
|
|
179
|
+
if systemctl is-active --quiet openclaw-gateway; then
|
|
180
|
+
echo -e " ${GREEN}✅ Gateway is running${NC}"
|
|
181
|
+
else
|
|
182
|
+
echo -e " ${RED}❌ Gateway failed to start!${NC}"
|
|
183
|
+
echo ""
|
|
184
|
+
echo -e "${RED} Checking logs:${NC}"
|
|
185
|
+
journalctl -u openclaw-gateway --no-pager -n 20
|
|
186
|
+
echo ""
|
|
187
|
+
echo -e "${YELLOW} To rollback:${NC}"
|
|
188
|
+
CURRENT_SEMVER=$(echo "$CURRENT_VERSION" | grep -oP '\d+\.\d+\.\d+' || echo "")
|
|
189
|
+
echo " systemctl stop openclaw-gateway"
|
|
190
|
+
if [ -n "$CURRENT_SEMVER" ]; then
|
|
191
|
+
echo " npm install -g openclaw@$CURRENT_SEMVER"
|
|
192
|
+
else
|
|
193
|
+
echo " npm install -g openclaw@<previous-version>"
|
|
194
|
+
fi
|
|
195
|
+
echo " cp ~/.openclaw/openclaw.json.pre-upgrade-$TIMESTAMP ~/.openclaw/openclaw.json"
|
|
196
|
+
echo " systemctl start openclaw-gateway"
|
|
197
|
+
exit 1
|
|
198
|
+
fi
|
|
199
|
+
fi
|
|
200
|
+
echo ""
|
|
201
|
+
|
|
202
|
+
# Step 8: Verify new version and health
|
|
203
|
+
echo -e "${YELLOW}[8/8] Post-upgrade verification...${NC}"
|
|
204
|
+
if $DRY_RUN; then
|
|
205
|
+
echo " [DRY RUN] Upgrade would go from $CURRENT_VERSION → $LATEST_VERSION"
|
|
206
|
+
else
|
|
207
|
+
NEW_VERSION=$(openclaw --version 2>&1 || echo "unknown")
|
|
208
|
+
echo " Previous: $CURRENT_VERSION"
|
|
209
|
+
echo " Current: $NEW_VERSION"
|
|
210
|
+
fi
|
|
211
|
+
echo ""
|
|
212
|
+
|
|
213
|
+
# Check that config keys are intact
|
|
214
|
+
echo " Checking config integrity..."
|
|
215
|
+
if [ -f ~/.openclaw/openclaw.json ]; then
|
|
216
|
+
if python3 -c "
|
|
217
|
+
import json, sys
|
|
218
|
+
with open('$HOME/.openclaw/openclaw.json') as f:
|
|
219
|
+
cfg = json.load(f)
|
|
220
|
+
|
|
221
|
+
issues = []
|
|
222
|
+
if not cfg.get('gateway', {}).get('controlUi', {}).get('allowedOrigins'):
|
|
223
|
+
issues.append('gateway.controlUi.allowedOrigins missing')
|
|
224
|
+
|
|
225
|
+
if not cfg.get('plugins', {}).get('allow'):
|
|
226
|
+
issues.append('plugins.allow missing or empty')
|
|
227
|
+
|
|
228
|
+
if issues:
|
|
229
|
+
for i in issues:
|
|
230
|
+
print(f' ⚠️ {i}')
|
|
231
|
+
sys.exit(1)
|
|
232
|
+
else:
|
|
233
|
+
print(' ✅ controlUi.allowedOrigins present')
|
|
234
|
+
print(' ✅ plugins.allow present')
|
|
235
|
+
" 2>/dev/null; then
|
|
236
|
+
:
|
|
237
|
+
else
|
|
238
|
+
echo -e " ${YELLOW}⚠️ Config may need manual review${NC}"
|
|
239
|
+
fi
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
echo ""
|
|
243
|
+
if $DRY_RUN; then
|
|
244
|
+
echo -e "${YELLOW}════════════════════════════════════════════════════${NC}"
|
|
245
|
+
echo -e "${YELLOW} DRY RUN COMPLETE — no changes were made ${NC}"
|
|
246
|
+
echo -e "${YELLOW} Run without --dry-run to apply ${NC}"
|
|
247
|
+
echo -e "${YELLOW}════════════════════════════════════════════════════${NC}"
|
|
248
|
+
else
|
|
249
|
+
echo -e "${GREEN}════════════════════════════════════════════════════${NC}"
|
|
250
|
+
echo -e "${GREEN} Upgrade complete: ${NEW_VERSION:-$LATEST_VERSION}${NC}"
|
|
251
|
+
echo -e "${GREEN}════════════════════════════════════════════════════${NC}"
|
|
252
|
+
echo ""
|
|
253
|
+
echo " Backups saved with timestamp: $TIMESTAMP"
|
|
254
|
+
echo " To clean up old backups later:"
|
|
255
|
+
echo " ls ~/.openclaw/*.pre-upgrade-*"
|
|
256
|
+
echo " ls -d ~/.openclaw/extensions.pre-upgrade-* 2>/dev/null"
|
|
257
|
+
echo " ls -d ~/.openclaw/agents.pre-upgrade-* 2>/dev/null"
|
|
258
|
+
echo ""
|
|
259
|
+
echo " Mighty Mark's next morning check will verify the upgrade."
|
|
260
|
+
echo " To check immediately:"
|
|
261
|
+
echo " openclaw tool mark_health"
|
|
262
|
+
fi
|
|
263
|
+
echo ""
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# validate-openclaw-config.sh — Validate openclaw.json before gateway restart
|
|
4
|
+
#
|
|
5
|
+
# Usage (on VPS):
|
|
6
|
+
# bash /opt/mighty-mark/validate-openclaw-config.sh
|
|
7
|
+
# bash /opt/mighty-mark/validate-openclaw-config.sh /path/to/openclaw.json
|
|
8
|
+
#
|
|
9
|
+
# This prevents Bug 10 (Rule 806): gateway crash from invalid config.
|
|
10
|
+
# OpenClaw uses strict Zod validation. Unknown keys or out-of-range values
|
|
11
|
+
# cause every agent to spam "Invalid config" errors on restart.
|
|
12
|
+
#
|
|
13
|
+
# Known schema constraints (OpenClaw 2026.3.x):
|
|
14
|
+
# agents.defaults.subagents.maxSpawnDepth: 1-5
|
|
15
|
+
# agents.defaults.subagents.maxChildrenPerAgent: 1-20
|
|
16
|
+
# agents.defaults.subagents: .strict() (no unknown keys)
|
|
17
|
+
# session.dmScope: "main" | "per-channel-peer"
|
|
18
|
+
# tools.exec.security: "full" | "allowlist" | "none"
|
|
19
|
+
|
|
20
|
+
set -euo pipefail
|
|
21
|
+
|
|
22
|
+
CONFIG_FILE="${1:-/root/.openclaw/openclaw.json}"
|
|
23
|
+
|
|
24
|
+
if [ ! -f "$CONFIG_FILE" ]; then
|
|
25
|
+
echo "❌ Config file not found: $CONFIG_FILE"
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
echo "=== OpenClaw Config Validation ==="
|
|
30
|
+
echo "File: $CONFIG_FILE"
|
|
31
|
+
echo ""
|
|
32
|
+
|
|
33
|
+
ERRORS=0
|
|
34
|
+
WARNINGS=0
|
|
35
|
+
|
|
36
|
+
# Check valid JSON
|
|
37
|
+
if ! python3 -c "import json; json.load(open('$CONFIG_FILE'))" 2>/dev/null; then
|
|
38
|
+
echo "❌ FATAL: File is not valid JSON"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
echo "✅ Valid JSON"
|
|
42
|
+
|
|
43
|
+
# Check known schema constraints using python3
|
|
44
|
+
python3 << 'PYEOF'
|
|
45
|
+
import json, sys
|
|
46
|
+
|
|
47
|
+
config_file = sys.argv[1] if len(sys.argv) > 1 else "/root/.openclaw/openclaw.json"
|
|
48
|
+
with open(config_file) as f:
|
|
49
|
+
cfg = json.load(f)
|
|
50
|
+
|
|
51
|
+
errors = []
|
|
52
|
+
warnings = []
|
|
53
|
+
|
|
54
|
+
# Check agents.defaults.subagents
|
|
55
|
+
defaults = cfg.get("agents", {}).get("defaults", {})
|
|
56
|
+
subagents = defaults.get("subagents", {})
|
|
57
|
+
|
|
58
|
+
if subagents:
|
|
59
|
+
known_keys = {"maxSpawnDepth", "maxChildrenPerAgent"}
|
|
60
|
+
unknown = set(subagents.keys()) - known_keys
|
|
61
|
+
for k in unknown:
|
|
62
|
+
errors.append(f"agents.defaults.subagents.{k}: Unknown key (OpenClaw uses .strict() — will be rejected)")
|
|
63
|
+
|
|
64
|
+
depth = subagents.get("maxSpawnDepth")
|
|
65
|
+
if depth is not None:
|
|
66
|
+
if not isinstance(depth, (int, float)) or depth < 1 or depth > 5:
|
|
67
|
+
errors.append(f"agents.defaults.subagents.maxSpawnDepth={depth}: must be 1-5")
|
|
68
|
+
|
|
69
|
+
children = subagents.get("maxChildrenPerAgent")
|
|
70
|
+
if children is not None:
|
|
71
|
+
if not isinstance(children, (int, float)) or children < 1 or children > 20:
|
|
72
|
+
errors.append(f"agents.defaults.subagents.maxChildrenPerAgent={children}: must be 1-20")
|
|
73
|
+
|
|
74
|
+
# Check session.dmScope
|
|
75
|
+
session = cfg.get("session", {})
|
|
76
|
+
dm_scope = session.get("dmScope")
|
|
77
|
+
if dm_scope and dm_scope not in ("main", "per-channel-peer"):
|
|
78
|
+
errors.append(f"session.dmScope={dm_scope}: must be 'main' or 'per-channel-peer'")
|
|
79
|
+
|
|
80
|
+
# Check tools.exec.security
|
|
81
|
+
tools = cfg.get("tools", {}).get("exec", {})
|
|
82
|
+
security = tools.get("security")
|
|
83
|
+
if security and security not in ("full", "allowlist", "none"):
|
|
84
|
+
errors.append(f"tools.exec.security={security}: must be 'full', 'allowlist', or 'none'")
|
|
85
|
+
|
|
86
|
+
# Check agents.list exists and has entries
|
|
87
|
+
agents_list = cfg.get("agents", {}).get("list", [])
|
|
88
|
+
if not agents_list:
|
|
89
|
+
warnings.append("agents.list is empty — no agents configured")
|
|
90
|
+
|
|
91
|
+
# Report
|
|
92
|
+
if errors:
|
|
93
|
+
print("")
|
|
94
|
+
for e in errors:
|
|
95
|
+
print(f"❌ {e}")
|
|
96
|
+
print("")
|
|
97
|
+
print(f"RESULT: {len(errors)} error(s) found — DO NOT restart the gateway!")
|
|
98
|
+
print("Fix the config and re-run this script.")
|
|
99
|
+
sys.exit(1)
|
|
100
|
+
|
|
101
|
+
if warnings:
|
|
102
|
+
print("")
|
|
103
|
+
for w in warnings:
|
|
104
|
+
print(f"⚠️ {w}")
|
|
105
|
+
|
|
106
|
+
print("")
|
|
107
|
+
print("✅ Config passes known schema constraints")
|
|
108
|
+
print(" Run 'openclaw doctor' for full validation (includes constraints this script doesn't check)")
|
|
109
|
+
PYEOF
|
|
110
|
+
|
|
111
|
+
echo ""
|
|
112
|
+
echo "=== Also running 'openclaw doctor' for full validation ==="
|
|
113
|
+
if command -v openclaw &>/dev/null; then
|
|
114
|
+
openclaw doctor 2>&1 || true
|
|
115
|
+
else
|
|
116
|
+
echo "⚠️ 'openclaw' command not found — skipping full validation"
|
|
117
|
+
echo " Install with: npm install -g @aiassesstech/openclaw"
|
|
118
|
+
fi
|