@badgerclaw/connect 1.4.7 → 1.4.8

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