Auto-approve Discord pairing codes
Browse files- Dockerfile +3 -0
- discord-pairing-approve.mjs +71 -0
Dockerfile
CHANGED
|
@@ -23,6 +23,7 @@ COPY setup-hf-config.mjs /app/setup-hf-config.mjs
|
|
| 23 |
COPY resolve-telegram-host.mjs /app/resolve-telegram-host.mjs
|
| 24 |
COPY resolve-discord-host.mjs /app/resolve-discord-host.mjs
|
| 25 |
COPY discord-bot-init.mjs /app/discord-bot-init.mjs
|
|
|
|
| 26 |
COPY discord-startup-notify.mjs /app/discord-startup-notify.mjs
|
| 27 |
COPY import-auth-profiles.mjs /app/import-auth-profiles.mjs
|
| 28 |
COPY startup-notify.mjs /app/startup-notify.mjs
|
|
@@ -68,6 +69,8 @@ RUN printf '%s\n' \
|
|
| 68 |
'node /app/import-auth-profiles.mjs' \
|
| 69 |
'echo "[openclaw-entrypoint] step=import-auth-profiles status=ok"' \
|
| 70 |
'run_optional startup-notify node /app/startup-notify.mjs' \
|
|
|
|
|
|
|
| 71 |
'run_optional discord-startup-notify node /app/discord-startup-notify.mjs' \
|
| 72 |
'if [ "${OPENCLAW_ENABLE_GEMINI_CLI_AUTH:-1}" = "1" ]; then' \
|
| 73 |
' echo "[openclaw-entrypoint] step=enable-gemini-cli-auth status=start"' \
|
|
|
|
| 23 |
COPY resolve-telegram-host.mjs /app/resolve-telegram-host.mjs
|
| 24 |
COPY resolve-discord-host.mjs /app/resolve-discord-host.mjs
|
| 25 |
COPY discord-bot-init.mjs /app/discord-bot-init.mjs
|
| 26 |
+
COPY discord-pairing-approve.mjs /app/discord-pairing-approve.mjs
|
| 27 |
COPY discord-startup-notify.mjs /app/discord-startup-notify.mjs
|
| 28 |
COPY import-auth-profiles.mjs /app/import-auth-profiles.mjs
|
| 29 |
COPY startup-notify.mjs /app/startup-notify.mjs
|
|
|
|
| 69 |
'node /app/import-auth-profiles.mjs' \
|
| 70 |
'echo "[openclaw-entrypoint] step=import-auth-profiles status=ok"' \
|
| 71 |
'run_optional startup-notify node /app/startup-notify.mjs' \
|
| 72 |
+
'echo "[openclaw-entrypoint] step=discord-pairing-approve status=start background=1"' \
|
| 73 |
+
'node /app/discord-pairing-approve.mjs 2>&1 &' \
|
| 74 |
'run_optional discord-startup-notify node /app/discord-startup-notify.mjs' \
|
| 75 |
'if [ "${OPENCLAW_ENABLE_GEMINI_CLI_AUTH:-1}" = "1" ]; then' \
|
| 76 |
' echo "[openclaw-entrypoint] step=enable-gemini-cli-auth status=start"' \
|
discord-pairing-approve.mjs
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
import { execFile } from "node:child_process";
|
| 3 |
+
import { promisify } from "node:util";
|
| 4 |
+
|
| 5 |
+
const execFileAsync = promisify(execFile);
|
| 6 |
+
const code =
|
| 7 |
+
process.env.DISCORD_BOT_PAIRINGCODE?.trim() ||
|
| 8 |
+
process.env.OPENCLAW_DISCORD_PAIRING_CODE?.trim() ||
|
| 9 |
+
"";
|
| 10 |
+
const maxAttempts = Number.parseInt(process.env.OPENCLAW_DISCORD_PAIRING_APPROVE_ATTEMPTS || "30", 10);
|
| 11 |
+
const intervalMs = Number.parseInt(process.env.OPENCLAW_DISCORD_PAIRING_APPROVE_INTERVAL_MS || "10000", 10);
|
| 12 |
+
|
| 13 |
+
function sleep(ms) {
|
| 14 |
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
async function runOpenClaw(args) {
|
| 18 |
+
return execFileAsync("openclaw", args, { timeout: 20000 });
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
async function main() {
|
| 22 |
+
if (!code) {
|
| 23 |
+
console.log("[openclaw-discord-pairing] skipped code=0");
|
| 24 |
+
return;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
console.log(
|
| 28 |
+
`[openclaw-discord-pairing] status=start code_present=1 attempts=${maxAttempts} interval_ms=${intervalMs}`,
|
| 29 |
+
);
|
| 30 |
+
|
| 31 |
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
| 32 |
+
try {
|
| 33 |
+
const { stdout } = await runOpenClaw(["pairing", "approve", "discord", code]);
|
| 34 |
+
console.log(
|
| 35 |
+
`[openclaw-discord-pairing] status=approved attempt=${attempt} output=${JSON.stringify(
|
| 36 |
+
(stdout || "").trim(),
|
| 37 |
+
)}`,
|
| 38 |
+
);
|
| 39 |
+
return;
|
| 40 |
+
} catch (error) {
|
| 41 |
+
const stderr =
|
| 42 |
+
error && typeof error === "object" && "stderr" in error ? String(error.stderr || "").trim() : "";
|
| 43 |
+
const stdout =
|
| 44 |
+
error && typeof error === "object" && "stdout" in error ? String(error.stdout || "").trim() : "";
|
| 45 |
+
const message = stderr || stdout || (error instanceof Error ? error.message : String(error));
|
| 46 |
+
console.warn(
|
| 47 |
+
`[openclaw-discord-pairing] status=retry attempt=${attempt} reason=${JSON.stringify(message)}`,
|
| 48 |
+
);
|
| 49 |
+
|
| 50 |
+
const normalized = message.toLowerCase();
|
| 51 |
+
if (
|
| 52 |
+
normalized.includes("expired") ||
|
| 53 |
+
normalized.includes("not found") ||
|
| 54 |
+
normalized.includes("invalid")
|
| 55 |
+
) {
|
| 56 |
+
console.warn(
|
| 57 |
+
`[openclaw-discord-pairing] status=stop attempt=${attempt} reason=${JSON.stringify(message)}`,
|
| 58 |
+
);
|
| 59 |
+
return;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
if (attempt < maxAttempts) {
|
| 63 |
+
await sleep(intervalMs);
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
console.warn(`[openclaw-discord-pairing] status=timeout attempts=${maxAttempts}`);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
await main();
|