-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathdiagnose.js
More file actions
193 lines (174 loc) · 8.17 KB
/
diagnose.js
File metadata and controls
193 lines (174 loc) · 8.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/usr/bin/env node
// diagnose.js — Check every part of the OpenVoiceUI + OpenClaw connection chain.
// Run this after containers are up to find exactly where things break.
//
// Usage: node diagnose.js
const { execSync } = require("child_process");
const fs = require("fs");
const path = require("path");
const COMPOSE = "docker compose -f docker-compose.yml -f docker-compose.local.yml";
let failures = 0;
function check(name, fn) {
try {
const result = fn();
console.log(` ✅ ${name}${result ? ': ' + result : ''}`);
return true;
} catch (e) {
console.log(` ❌ ${name}: ${e.message}`);
failures++;
return false;
}
}
function exec(cmd, opts = {}) {
return execSync(cmd, { encoding: "utf8", timeout: 15000, ...opts }).trim();
}
console.log("\n=== OpenVoiceUI Pinokio Diagnostics ===\n");
// --- 1. Config files exist ---
console.log("1. Config files:");
check("openclaw.json exists", () => {
if (!fs.existsSync("openclaw-data/openclaw.json")) throw new Error("MISSING — run install first");
return "ok";
});
check(".env exists", () => {
if (!fs.existsSync(".env")) throw new Error("MISSING — run install first");
return "ok";
});
check("auth-profiles.json exists", () => {
const p = "openclaw-data/agents/main/agent/auth-profiles.json";
if (!fs.existsSync(p)) throw new Error("MISSING");
const data = JSON.parse(fs.readFileSync(p, "utf8"));
return `${Object.keys(data).length} provider(s)`;
});
check("devices/paired.json exists", () => {
const p = "openclaw-data/devices/paired.json";
if (!fs.existsSync(p)) throw new Error("MISSING — device pairing will fail");
const data = JSON.parse(fs.readFileSync(p, "utf8"));
return `${Object.keys(data).length} paired device(s)`;
});
check("pre-paired-device.json exists", () => {
if (!fs.existsSync("openclaw-data/pre-paired-device.json")) throw new Error("MISSING — inject will fail");
return "ok";
});
// --- 2. Auth token consistency ---
console.log("\n2. Auth token match:");
check("tokens match between .env and openclaw.json", () => {
const env = fs.readFileSync(".env", "utf8");
const tokenMatch = env.match(/CLAWDBOT_AUTH_TOKEN=(.+)/);
if (!tokenMatch) throw new Error(".env missing CLAWDBOT_AUTH_TOKEN");
const envToken = tokenMatch[1].trim();
const config = JSON.parse(fs.readFileSync("openclaw-data/openclaw.json", "utf8"));
const configToken = config?.gateway?.auth?.token;
if (!configToken) throw new Error("openclaw.json missing gateway.auth.token");
if (envToken !== configToken) throw new Error(`MISMATCH! .env="${envToken.slice(0,8)}..." vs config="${configToken.slice(0,8)}..."`);
return `both = ${envToken.slice(0, 8)}...`;
});
// --- 3. OpenClaw config validation ---
console.log("\n3. OpenClaw config:");
check("openclaw.json structure", () => {
const config = JSON.parse(fs.readFileSync("openclaw-data/openclaw.json", "utf8"));
const issues = [];
if (!config.gateway) issues.push("missing gateway");
if (!config.agents) issues.push("missing agents");
if (!config.gateway?.auth?.token) issues.push("missing gateway.auth.token");
if (!config.gateway?.controlUi?.dangerouslyDisableDeviceAuth) issues.push("missing dangerouslyDisableDeviceAuth");
if (!config.agents?.defaults?.thinkingDefault) issues.push("missing thinkingDefault");
if (!config.agents?.defaults?.model) issues.push("missing default model");
if (issues.length) throw new Error(issues.join(", "));
return `model=${config.agents.defaults.model}`;
});
// --- 4. Device identity consistency ---
console.log("\n4. Device identity:");
check("pre-paired identity matches paired.json", () => {
const identity = JSON.parse(fs.readFileSync("openclaw-data/pre-paired-device.json", "utf8"));
const paired = JSON.parse(fs.readFileSync("openclaw-data/devices/paired.json", "utf8"));
if (!paired[identity.deviceId]) throw new Error(`deviceId ${identity.deviceId.slice(0,16)}... NOT in paired.json`);
return `deviceId=${identity.deviceId.slice(0, 16)}... is paired`;
});
// --- 5. Containers running ---
console.log("\n5. Containers:");
check("openclaw container running", () => {
const out = exec(`${COMPOSE} ps --format json openclaw 2>/dev/null || echo ""`);
if (!out || out.includes('"State":"exited"') || !out.includes('"State":"running"'))
throw new Error("NOT RUNNING");
return "running";
});
check("openvoiceui container running", () => {
const out = exec(`${COMPOSE} ps --format json openvoiceui 2>/dev/null || echo ""`);
if (!out || out.includes('"State":"exited"') || !out.includes('"State":"running"'))
throw new Error("NOT RUNNING");
return "running";
});
// --- 6. Gateway health ---
console.log("\n6. Gateway health:");
check("openclaw gateway responding on 18791", () => {
const out = exec(`${COMPOSE} exec -T openclaw node -e "const h=require('http');h.get('http://localhost:18791',r=>{console.log(r.statusCode);process.exit(0)}).on('error',e=>{console.log('ERROR:'+e.message);process.exit(1)})"`);
if (out.includes("ERROR")) throw new Error(out);
return `HTTP ${out}`;
});
// --- 7. OpenVoiceUI health ---
console.log("\n7. OpenVoiceUI health:");
check("flask app responding on 5001", () => {
const port = (fs.readFileSync(".env", "utf8").match(/PORT=(\d+)/) || [, "5001"])[1];
const out = exec(`${COMPOSE} exec -T openvoiceui python3 -c "import urllib.request; r=urllib.request.urlopen('http://localhost:${port}/health/ready',timeout=5); print(r.status)"`);
if (!out.includes("200")) throw new Error(`got ${out}`);
return `HTTP ${out}`;
});
// --- 8. Device identity in container ---
console.log("\n8. Device identity injection:");
check("identity file in openvoiceui container", () => {
const out = exec(`${COMPOSE} exec -T openvoiceui sh -c 'cat /app/runtime/uploads/.device-identity.json 2>/dev/null || echo MISSING'`);
if (out === "MISSING") throw new Error("NOT INJECTED — inject-device-identity.js may have failed");
const data = JSON.parse(out);
return `deviceId=${data.deviceId.slice(0, 16)}...`;
});
check("container identity matches paired.json", () => {
const containerOut = exec(`${COMPOSE} exec -T openvoiceui sh -c 'cat /app/runtime/uploads/.device-identity.json 2>/dev/null || echo "{}"'`);
const containerIdentity = JSON.parse(containerOut);
if (!containerIdentity.deviceId) throw new Error("no identity in container");
const paired = JSON.parse(fs.readFileSync("openclaw-data/devices/paired.json", "utf8"));
if (!paired[containerIdentity.deviceId]) throw new Error(`container deviceId ${containerIdentity.deviceId.slice(0,16)}... NOT in paired.json`);
return "matched";
});
// --- 9. Gateway connection test ---
console.log("\n9. Gateway connection test:");
check("openvoiceui can reach openclaw gateway", () => {
const out = exec(`${COMPOSE} exec -T openvoiceui python3 -c "
import asyncio, websockets, json, os
async def test():
url = os.getenv('CLAWDBOT_GATEWAY_URL', 'ws://127.0.0.1:18791')
try:
async with websockets.connect(url, open_timeout=5) as ws:
msg = json.loads(await asyncio.wait_for(ws.recv(), timeout=5))
if 'challenge' in str(msg.get('event','')):
print('CHALLENGE_OK')
else:
print('UNEXPECTED:' + json.dumps(msg)[:100])
except Exception as e:
print('FAIL:' + str(e))
asyncio.run(test())
"`, { timeout: 20000 });
if (out.includes("FAIL")) throw new Error(out);
if (!out.includes("CHALLENGE_OK")) throw new Error(`unexpected: ${out}`);
return "received challenge";
});
// --- 10. Recent logs ---
console.log("\n10. Recent container logs (last 20 lines each):");
try {
console.log("\n --- openclaw logs ---");
const clawLogs = exec(`${COMPOSE} logs --tail=20 openclaw 2>&1`);
console.log(" " + clawLogs.split("\n").join("\n "));
} catch (e) {
console.log(" (could not read openclaw logs)");
}
try {
console.log("\n --- openvoiceui logs ---");
const ovuLogs = exec(`${COMPOSE} logs --tail=20 openvoiceui 2>&1`);
console.log(" " + ovuLogs.split("\n").join("\n "));
} catch (e) {
console.log(" (could not read openvoiceui logs)");
}
// --- Summary ---
console.log(`\n=== Summary: ${failures === 0 ? 'All checks passed ✅' : `${failures} failure(s) ❌`} ===\n`);
if (failures > 0) {
console.log("Fix the ❌ items above. The first failure is usually the root cause.\n");
}