@badgerclaw/connect 1.2.2 → 1.2.4
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/SETUP.md +4 -2
- package/package.json +1 -1
- package/src/matrix/monitor/bot-commands.ts +116 -22
package/SETUP.md
CHANGED
|
@@ -97,8 +97,9 @@ Use these commands in any BadgerClaw room or DM where your bot is present.
|
|
|
97
97
|
| Command | Description |
|
|
98
98
|
|---------|-------------|
|
|
99
99
|
| `/bot help` | Show all available commands |
|
|
100
|
-
| `/bot talk on` | **Enable auto-reply** — bot responds to every message without needing an @mention.
|
|
101
|
-
| `/bot talk
|
|
100
|
+
| `/bot talk on` | **Enable auto-reply** — bot responds to every message without needing an @mention. If multiple bots are in the room, you'll be asked to specify which one. |
|
|
101
|
+
| `/bot talk on @botname` | **Enable auto-reply for a specific bot** — use when multiple bots are in the room. |
|
|
102
|
+
| `/bot talk off` | **Disable auto-reply for ALL bots** — kill switch. All bots in the room go quiet and only respond when @mentioned. |
|
|
102
103
|
| `/bot add <name>` | Invite a bot to the current room (e.g. `/bot add jarvis`) |
|
|
103
104
|
| `/bot list` | List all your bots and their connection status |
|
|
104
105
|
|
|
@@ -106,6 +107,7 @@ Use these commands in any BadgerClaw room or DM where your bot is present.
|
|
|
106
107
|
|
|
107
108
|
- **New installs:** Auto-reply is **ON by default** in all rooms
|
|
108
109
|
- **Per-room toggle:** `/bot talk on` and `/bot talk off` override the default for that specific room
|
|
110
|
+
- **Multi-bot rooms:** If multiple bots are present, `/bot talk on` asks which bot to enable. `/bot talk off` silences all bots at once.
|
|
109
111
|
- **@mentions always work:** Even with auto-reply off, the bot responds when @mentioned
|
|
110
112
|
|
|
111
113
|
---
|
package/package.json
CHANGED
|
@@ -80,21 +80,21 @@ export async function handleBotCommand(params: {
|
|
|
80
80
|
" Works in: Any room or DM",
|
|
81
81
|
"",
|
|
82
82
|
"/bot talk on",
|
|
83
|
-
" Enable auto-reply
|
|
84
|
-
" message
|
|
85
|
-
"
|
|
83
|
+
" Enable auto-reply for this bot. It will respond to",
|
|
84
|
+
" every message without needing an @mention.",
|
|
85
|
+
" If multiple bots are in the room, specify which one:",
|
|
86
|
+
" /bot talk on @botname",
|
|
86
87
|
" Works in: Any room or DM",
|
|
87
88
|
"",
|
|
88
89
|
"/bot talk off",
|
|
89
|
-
" Disable auto-reply
|
|
90
|
-
" when @mentioned.
|
|
91
|
-
" you don't want the bot responding to everything.",
|
|
90
|
+
" Disable auto-reply for ALL bots in this room.",
|
|
91
|
+
" Bots will only respond when @mentioned.",
|
|
92
92
|
" Works in: Any room or DM",
|
|
93
93
|
"",
|
|
94
94
|
"/bot add <botname>",
|
|
95
|
-
" Invite a bot to the current room.
|
|
96
|
-
" will be @<botname>_bot on this server.",
|
|
95
|
+
" Invite a bot to the current room.",
|
|
97
96
|
" Example: /bot add jarvis → invites @jarvis_bot",
|
|
97
|
+
" Also accepts: /bot add @jarvis_bot",
|
|
98
98
|
" Works in: Any room",
|
|
99
99
|
"",
|
|
100
100
|
"━━━ BotBadger DM Only ━━━",
|
|
@@ -116,9 +116,8 @@ export async function handleBotCommand(params: {
|
|
|
116
116
|
" Works in: Direct message with BotBadger only",
|
|
117
117
|
"",
|
|
118
118
|
"/bot list",
|
|
119
|
-
" List all
|
|
120
|
-
" 🟢
|
|
121
|
-
" 🔴 Not connected — bot needs pairing",
|
|
119
|
+
" List all bots in this room.",
|
|
120
|
+
" 🟢 = this bot 🤖 = other bots",
|
|
122
121
|
" Works in: Any room or DM",
|
|
123
122
|
].join("\n"),
|
|
124
123
|
});
|
|
@@ -126,20 +125,70 @@ export async function handleBotCommand(params: {
|
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
case "talk": {
|
|
128
|
+
// Resolve bot members in the room
|
|
129
|
+
const botSuffix = "_bot:badger.signout.io";
|
|
130
|
+
let roomBots: string[] = [];
|
|
131
|
+
try {
|
|
132
|
+
const members = await client.getJoinedRoomMembers(roomId);
|
|
133
|
+
roomBots = members.filter((m: string) => m.includes(botSuffix) && m !== selfUserId);
|
|
134
|
+
} catch {
|
|
135
|
+
// If we can't list members, proceed as single-bot
|
|
136
|
+
}
|
|
137
|
+
const multipleBots = roomBots.length > 0; // other bots besides self
|
|
138
|
+
|
|
139
|
+
// Check if a specific bot was mentioned: /bot talk on @botname
|
|
140
|
+
const mentionArg = parts.slice(3).join(" ").trim();
|
|
141
|
+
const mentionedBot = mentionArg
|
|
142
|
+
? mentionArg.startsWith("@") ? mentionArg : `@${mentionArg}`
|
|
143
|
+
: null;
|
|
144
|
+
|
|
145
|
+
// If a bot was mentioned and it's not us, ignore the command (let that bot handle it)
|
|
146
|
+
if (mentionedBot) {
|
|
147
|
+
const mentionLower = mentionedBot.toLowerCase();
|
|
148
|
+
const selfLower = selfUserId.toLowerCase();
|
|
149
|
+
// Match full userId or just the localpart
|
|
150
|
+
const selfLocalpart = selfLower.split(":")[0]; // @test_bot
|
|
151
|
+
if (!selfLower.startsWith(mentionLower) && !mentionLower.startsWith(selfLocalpart)) {
|
|
152
|
+
// Not addressed to us — ignore silently
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
129
157
|
if (arg === "on") {
|
|
158
|
+
// Multiple bots + no specific mention → ask which bot
|
|
159
|
+
if (multipleBots && !mentionedBot) {
|
|
160
|
+
const allBots = [selfUserId, ...roomBots];
|
|
161
|
+
const botList = allBots
|
|
162
|
+
.map((b, i) => ` ${i + 1}. ${b.split(":")[0]}`)
|
|
163
|
+
.join("\n");
|
|
164
|
+
await client.sendMessage(roomId, {
|
|
165
|
+
msgtype: "m.text",
|
|
166
|
+
body: [
|
|
167
|
+
"🦡 Multiple bots in this room:",
|
|
168
|
+
"",
|
|
169
|
+
botList,
|
|
170
|
+
"",
|
|
171
|
+
"Specify which bot: /bot talk on @botname",
|
|
172
|
+
].join("\n"),
|
|
173
|
+
});
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
130
177
|
const config = loadRoomConfig();
|
|
131
|
-
// Store with lowercase key to match OpenClaw's lowercased groupId
|
|
132
178
|
const normalizedRoomId = roomId.toLowerCase();
|
|
133
179
|
config[normalizedRoomId] = { ...config[normalizedRoomId], autoReply: true };
|
|
134
180
|
saveRoomConfig(config);
|
|
135
181
|
setGroupActivation(roomId, "always");
|
|
182
|
+
const selfName = selfUserId.split(":")[0];
|
|
136
183
|
await client.sendMessage(roomId, {
|
|
137
184
|
msgtype: "m.text",
|
|
138
|
-
body:
|
|
185
|
+
body: `✅ Auto-reply enabled for ${selfName} — I'll respond to every message in this room.`,
|
|
139
186
|
});
|
|
140
187
|
return true;
|
|
141
188
|
}
|
|
189
|
+
|
|
142
190
|
if (arg === "off") {
|
|
191
|
+
// Off is a kill switch — disable auto-reply regardless of how many bots
|
|
143
192
|
const config = loadRoomConfig();
|
|
144
193
|
const normalizedRoomId = roomId.toLowerCase();
|
|
145
194
|
config[normalizedRoomId] = { ...config[normalizedRoomId], autoReply: false };
|
|
@@ -147,43 +196,88 @@ export async function handleBotCommand(params: {
|
|
|
147
196
|
setGroupActivation(roomId, "mention");
|
|
148
197
|
await client.sendMessage(roomId, {
|
|
149
198
|
msgtype: "m.text",
|
|
150
|
-
body: "✅ Auto-reply disabled —
|
|
199
|
+
body: "✅ Auto-reply disabled for all bots — bots will only respond when @mentioned.",
|
|
151
200
|
});
|
|
152
201
|
return true;
|
|
153
202
|
}
|
|
203
|
+
|
|
154
204
|
await client.sendMessage(roomId, {
|
|
155
205
|
msgtype: "m.text",
|
|
156
|
-
body: "Usage: /bot talk on or /bot talk off",
|
|
206
|
+
body: "Usage: /bot talk on [@botname] or /bot talk off",
|
|
157
207
|
});
|
|
158
208
|
return true;
|
|
159
209
|
}
|
|
160
210
|
|
|
161
211
|
case "add": {
|
|
162
|
-
|
|
163
|
-
if (!
|
|
212
|
+
let rawName = parts.slice(2).join(" ").trim();
|
|
213
|
+
if (!rawName) {
|
|
164
214
|
await client.sendMessage(roomId, {
|
|
165
215
|
msgtype: "m.text",
|
|
166
|
-
body: "Usage: /bot add <botname
|
|
216
|
+
body: "Usage: /bot add <botname>\nExample: /bot add jarvis or /bot add @jarvis_bot",
|
|
167
217
|
});
|
|
168
218
|
return true;
|
|
169
219
|
}
|
|
170
|
-
|
|
220
|
+
// Normalize: strip @, strip _bot suffix, strip :server
|
|
221
|
+
rawName = rawName.replace(/^@/, "").split(":")[0].replace(/_bot$/i, "").toLowerCase();
|
|
222
|
+
const addBotUserId = `@${rawName}_bot:badger.signout.io`;
|
|
223
|
+
const addBotDisplay = `@${rawName}_bot`;
|
|
171
224
|
try {
|
|
172
|
-
await client.inviteUser(
|
|
225
|
+
await client.inviteUser(addBotUserId, roomId);
|
|
173
226
|
await client.sendMessage(roomId, {
|
|
174
227
|
msgtype: "m.text",
|
|
175
|
-
body: `✅ Invited ${
|
|
228
|
+
body: `✅ Invited ${addBotDisplay} to this room.`,
|
|
176
229
|
});
|
|
177
230
|
} catch (err) {
|
|
178
231
|
const msg = err instanceof Error ? err.message : String(err);
|
|
232
|
+
// Strip homeserver from error messages too
|
|
233
|
+
const cleanMsg = msg.replace(/:badger\.signout\.io/g, "");
|
|
179
234
|
await client.sendMessage(roomId, {
|
|
180
235
|
msgtype: "m.text",
|
|
181
|
-
body: `❌ Failed to invite ${
|
|
236
|
+
body: `❌ Failed to invite ${addBotDisplay}: ${cleanMsg}`,
|
|
182
237
|
});
|
|
183
238
|
}
|
|
184
239
|
return true;
|
|
185
240
|
}
|
|
186
241
|
|
|
242
|
+
case "list": {
|
|
243
|
+
const botSuffix2 = "_bot:badger.signout.io";
|
|
244
|
+
let botsInRoom: string[] = [];
|
|
245
|
+
try {
|
|
246
|
+
const members = await client.getJoinedRoomMembers(roomId);
|
|
247
|
+
botsInRoom = members.filter((m: string) => m.includes(botSuffix2));
|
|
248
|
+
} catch {
|
|
249
|
+
botsInRoom = [selfUserId]; // At minimum, we know we're here
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (botsInRoom.length === 0) {
|
|
253
|
+
await client.sendMessage(roomId, {
|
|
254
|
+
msgtype: "m.text",
|
|
255
|
+
body: "No bots in this room.",
|
|
256
|
+
});
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const botList = botsInRoom
|
|
261
|
+
.map((b) => {
|
|
262
|
+
const displayName = b.split(":")[0];
|
|
263
|
+
const isMe = b === selfUserId;
|
|
264
|
+
return ` ${isMe ? "🟢" : "🤖"} ${displayName}${isMe ? " (me)" : ""}`;
|
|
265
|
+
})
|
|
266
|
+
.join("\n");
|
|
267
|
+
|
|
268
|
+
await client.sendMessage(roomId, {
|
|
269
|
+
msgtype: "m.text",
|
|
270
|
+
body: [
|
|
271
|
+
"🦡 Bots in this room:",
|
|
272
|
+
"",
|
|
273
|
+
botList,
|
|
274
|
+
"",
|
|
275
|
+
`${botsInRoom.length} bot${botsInRoom.length === 1 ? "" : "s"} total`,
|
|
276
|
+
].join("\n"),
|
|
277
|
+
});
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
|
|
187
281
|
default: {
|
|
188
282
|
// Unknown /bot command — show help hint
|
|
189
283
|
await client.sendMessage(roomId, {
|