@badgerclaw/connect 1.4.7 → 1.4.9
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/index.ts +91 -0
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -4,6 +4,95 @@ import { matrixPlugin } from "./src/channel.js";
|
|
|
4
4
|
import { ensureMatrixCryptoRuntime } from "./src/matrix/deps.js";
|
|
5
5
|
import { setMatrixRuntime } from "./src/runtime.js";
|
|
6
6
|
|
|
7
|
+
let _pairWatcherStarted = false;
|
|
8
|
+
|
|
9
|
+
async function startPairWatcher(logger: { info?: (msg: string) => void; warn?: (msg: string) => void }): Promise<void> {
|
|
10
|
+
if (_pairWatcherStarted) return;
|
|
11
|
+
_pairWatcherStarted = true;
|
|
12
|
+
const log = logger.info ?? console.log;
|
|
13
|
+
const warn = logger.warn ?? console.warn;
|
|
14
|
+
|
|
15
|
+
// Load JWT from ~/.badgerclaw/auth.json — written by `badgerclaw login`
|
|
16
|
+
let token: string | null = null;
|
|
17
|
+
try {
|
|
18
|
+
const fs = await import("fs");
|
|
19
|
+
const path = await import("path");
|
|
20
|
+
const os = await import("os");
|
|
21
|
+
const authPath = path.join(os.homedir(), ".badgerclaw", "auth.json");
|
|
22
|
+
if (fs.existsSync(authPath)) {
|
|
23
|
+
const auth = JSON.parse(fs.readFileSync(authPath, "utf-8"));
|
|
24
|
+
token = auth.access_token ?? null;
|
|
25
|
+
}
|
|
26
|
+
} catch {}
|
|
27
|
+
|
|
28
|
+
if (!token) {
|
|
29
|
+
log("badgerclaw: no CLI auth found — run `badgerclaw login` to enable auto-pair");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const API_BASE = "https://api.badgerclaw.ai";
|
|
34
|
+
log("badgerclaw: pair-watcher started — listening for pair events from iOS app");
|
|
35
|
+
|
|
36
|
+
const connect = () => {
|
|
37
|
+
const EventSource = require("/opt/homebrew/lib/node_modules/badgerclaw/node_modules/eventsource");
|
|
38
|
+
const es = new EventSource(`${API_BASE}/api/v1/openclaw/events`, {
|
|
39
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
es.onmessage = async (event: any) => {
|
|
43
|
+
try {
|
|
44
|
+
const data = JSON.parse(event.data);
|
|
45
|
+
if (data.type !== "pair") return;
|
|
46
|
+
|
|
47
|
+
log(`badgerclaw: pair event received for ${data.bot_user_id}`);
|
|
48
|
+
|
|
49
|
+
// Redeem the code
|
|
50
|
+
const redeemResp = await fetch(`${API_BASE}/api/v1/pairing/redeem`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { "Content-Type": "application/json" },
|
|
53
|
+
body: JSON.stringify({ code: data.pair_code }),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!redeemResp.ok) {
|
|
57
|
+
warn(`badgerclaw: pair redeem failed: ${redeemResp.status}`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const bot = await redeemResp.json() as {
|
|
62
|
+
homeserver: string; access_token: string; user_id: string; bot_name: string; device_id: string;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Write to config via openclaw config set — triggers hot-reload, bot starts immediately
|
|
66
|
+
const { execSync } = await import("child_process");
|
|
67
|
+
const localpart = bot.user_id.split(":")[0].replace("@", "").replace(/_bot$/, "");
|
|
68
|
+
const base = `channels.badgerclaw.accounts.${localpart}`;
|
|
69
|
+
const opts = { encoding: "utf-8" as const, timeout: 10000, stdio: "pipe" as const };
|
|
70
|
+
execSync(`openclaw config set ${base}.userId "${bot.user_id}"`, opts);
|
|
71
|
+
execSync(`openclaw config set ${base}.accessToken "${bot.access_token}"`, opts);
|
|
72
|
+
execSync(`openclaw config set ${base}.homeserver "${bot.homeserver}"`, opts);
|
|
73
|
+
execSync(`openclaw config set ${base}.encryption true`, opts);
|
|
74
|
+
if (bot.device_id) execSync(`openclaw config set ${base}.deviceId "${bot.device_id}"`, opts);
|
|
75
|
+
|
|
76
|
+
// Mark claimed
|
|
77
|
+
await fetch(`${API_BASE}/api/v1/openclaw/pending-pairs/${data.pair_code}/claim`, {
|
|
78
|
+
method: "POST",
|
|
79
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
80
|
+
}).catch(() => {});
|
|
81
|
+
|
|
82
|
+
log(`badgerclaw: ✅ ${bot.bot_name} (${bot.user_id}) auto-paired and live`);
|
|
83
|
+
} catch (e) {
|
|
84
|
+
warn(`badgerclaw: pair event error: ${String(e)}`);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
es.onerror = () => {
|
|
89
|
+
// EventSource auto-reconnects — silent
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
connect();
|
|
94
|
+
}
|
|
95
|
+
|
|
7
96
|
async function checkPluginUpdate(log: (msg: string) => void): Promise<void> {
|
|
8
97
|
try {
|
|
9
98
|
const CURRENT = "1.4.4";
|
|
@@ -33,6 +122,8 @@ const plugin = {
|
|
|
33
122
|
register(api: OpenClawPluginApi) {
|
|
34
123
|
setMatrixRuntime(api.runtime);
|
|
35
124
|
void checkPluginUpdate(api.logger.info ?? console.log);
|
|
125
|
+
// Start SSE pair-watcher — no external process needed, runs inside OpenClaw gateway
|
|
126
|
+
void startPairWatcher(api.logger).catch(() => {});
|
|
36
127
|
void ensureMatrixCryptoRuntime({ log: api.logger.info }).catch((err) => {
|
|
37
128
|
const message = err instanceof Error ? err.message : String(err);
|
|
38
129
|
api.logger.warn?.(`badgerclaw: crypto runtime bootstrap failed: ${message}`);
|