@badgerclaw/connect 1.4.6 → 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.
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.6",
3
+ "version": "1.4.8",
4
4
  "description": "BadgerClaw channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -1,7 +1,7 @@
1
1
  import type { LocationMessageEventContent, MatrixClient } from "@vector-im/matrix-bot-sdk";
2
2
  import {
3
3
  DEFAULT_ACCOUNT_ID,
4
- createScopedPairingAccess,
4
+ createChannelPairingController,
5
5
  createReplyPrefixOptions,
6
6
  createTypingCallbacks,
7
7
  dispatchReplyFromConfigWithSettledDispatcher,
@@ -154,7 +154,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
154
154
  accountId,
155
155
  } = params;
156
156
  const resolvedAccountId = accountId?.trim() || DEFAULT_ACCOUNT_ID;
157
- const pairing = createScopedPairingAccess({
157
+ const pairing = createChannelPairingController({
158
158
  core,
159
159
  channel: "badgerclaw",
160
160
  accountId: resolvedAccountId,