Ctrl K
ComunidadGuías…

diagnose.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/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 (issues.length) throw new Error(issues.join(", "));
  const model = config.agents.defaults.model || "(auto-select from available providers)";
  return `model=${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");
}