@botcord/botcord 0.3.4 → 0.3.6-beta.20260413082920
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 +6 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
- package/skills/botcord/SKILL.md +78 -379
- package/skills/botcord-account/SKILL.md +172 -0
- package/skills/botcord-messaging/SKILL.md +188 -0
- package/skills/botcord-payment/SKILL.md +90 -0
- package/skills/botcord-social/SKILL.md +106 -0
- package/src/client.ts +101 -8
- package/src/commands/bind.ts +4 -3
- package/src/commands/uninstall.ts +129 -0
- package/src/constants.ts +1 -1
- package/src/credentials.ts +19 -146
- package/src/crypto.ts +1 -155
- package/src/hub-url.ts +1 -41
- package/src/inbound.ts +1 -10
- package/src/onboarding-hook.ts +106 -35
- package/src/session-key.ts +1 -59
- package/src/tools/account.ts +16 -32
- package/src/tools/api.ts +112 -0
- package/src/tools/bind.ts +11 -36
- package/src/tools/coin-format.ts +19 -0
- package/src/tools/contacts.ts +26 -37
- package/src/tools/directory.ts +9 -30
- package/src/tools/messaging.ts +25 -40
- package/src/tools/payment.ts +44 -43
- package/src/tools/register.ts +5 -4
- package/src/tools/reset-credential.ts +6 -5
- package/src/tools/room-context.ts +34 -35
- package/src/tools/rooms.ts +36 -42
- package/src/tools/subscription.ts +34 -43
- package/src/tools/tool-result.ts +10 -3
- package/src/tools/topics.ts +17 -31
- package/src/types.ts +3 -256
package/src/tools/rooms.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* botcord_rooms — Room lifecycle and membership management.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
resolveAccountConfig,
|
|
7
|
-
isAccountConfigured,
|
|
8
|
-
} from "../config.js";
|
|
9
|
-
import { BotCordClient } from "../client.js";
|
|
10
|
-
import { attachTokenPersistence } from "../credentials.js";
|
|
11
|
-
import { getConfig as getAppConfig } from "../runtime.js";
|
|
4
|
+
import { withClient } from "./with-client.js";
|
|
5
|
+
import { validationError, dryRunResult } from "./tool-result.js";
|
|
12
6
|
|
|
13
7
|
export function createRoomsTool() {
|
|
14
8
|
return {
|
|
@@ -102,27 +96,19 @@ export function createRoomsTool() {
|
|
|
102
96
|
type: "boolean" as const,
|
|
103
97
|
description: "Mute or unmute the current member in a room — for mute",
|
|
104
98
|
},
|
|
99
|
+
dry_run: {
|
|
100
|
+
type: "boolean" as const,
|
|
101
|
+
description: "Preview the request without executing. Returns the API call that would be made.",
|
|
102
|
+
},
|
|
105
103
|
},
|
|
106
104
|
required: ["action"],
|
|
107
105
|
},
|
|
108
106
|
execute: async (toolCallId: any, args: any, signal?: any, onUpdate?: any) => {
|
|
109
|
-
|
|
110
|
-
if (!cfg) return { error: "No configuration available" };
|
|
111
|
-
const singleAccountError = getSingleAccountModeError(cfg);
|
|
112
|
-
if (singleAccountError) return { error: singleAccountError };
|
|
113
|
-
|
|
114
|
-
const acct = resolveAccountConfig(cfg);
|
|
115
|
-
if (!isAccountConfigured(acct)) {
|
|
116
|
-
return { error: "BotCord is not configured." };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const client = new BotCordClient(acct);
|
|
120
|
-
attachTokenPersistence(client, acct);
|
|
121
|
-
|
|
122
|
-
try {
|
|
107
|
+
return withClient(async (client) => {
|
|
123
108
|
switch (args.action) {
|
|
124
109
|
case "create":
|
|
125
|
-
if (!args.name) return
|
|
110
|
+
if (!args.name) return validationError("name is required");
|
|
111
|
+
if (args.dry_run) return dryRunResult("POST", "/hub/rooms", { name: args.name, visibility: args.visibility || "private", join_policy: args.join_policy, member_ids: args.member_ids });
|
|
126
112
|
return await client.createRoom({
|
|
127
113
|
name: args.name,
|
|
128
114
|
description: args.description,
|
|
@@ -138,14 +124,15 @@ export function createRoomsTool() {
|
|
|
138
124
|
});
|
|
139
125
|
|
|
140
126
|
case "list":
|
|
141
|
-
return await client.listMyRooms();
|
|
127
|
+
return { rooms: await client.listMyRooms() };
|
|
142
128
|
|
|
143
129
|
case "info":
|
|
144
|
-
if (!args.room_id) return
|
|
130
|
+
if (!args.room_id) return validationError("room_id is required");
|
|
145
131
|
return await client.getRoomInfo(args.room_id);
|
|
146
132
|
|
|
147
133
|
case "update":
|
|
148
|
-
if (!args.room_id) return
|
|
134
|
+
if (!args.room_id) return validationError("room_id is required");
|
|
135
|
+
if (args.dry_run) return dryRunResult("PATCH", `/hub/rooms/${args.room_id}`, { name: args.name, description: args.description, rule: args.rule, visibility: args.visibility, join_policy: args.join_policy, required_subscription_product_id: args.required_subscription_product_id, max_members: args.max_members, default_send: args.default_send, default_invite: args.default_invite, slow_mode_seconds: args.slow_mode_seconds });
|
|
149
136
|
return await client.updateRoom(args.room_id, {
|
|
150
137
|
name: args.name,
|
|
151
138
|
description: args.description,
|
|
@@ -160,10 +147,11 @@ export function createRoomsTool() {
|
|
|
160
147
|
});
|
|
161
148
|
|
|
162
149
|
case "discover":
|
|
163
|
-
return await client.
|
|
150
|
+
return await client.discoverPublicRooms(args.name);
|
|
164
151
|
|
|
165
152
|
case "join":
|
|
166
|
-
if (!args.room_id) return
|
|
153
|
+
if (!args.room_id) return validationError("room_id is required");
|
|
154
|
+
if (args.dry_run) return dryRunResult("POST", `/hub/rooms/${args.room_id}/members`, { agent_id: "{self}" });
|
|
167
155
|
await client.joinRoom(args.room_id, {
|
|
168
156
|
can_send: args.can_send,
|
|
169
157
|
can_invite: args.can_invite,
|
|
@@ -171,21 +159,24 @@ export function createRoomsTool() {
|
|
|
171
159
|
return { ok: true, joined: args.room_id };
|
|
172
160
|
|
|
173
161
|
case "leave":
|
|
174
|
-
if (!args.room_id) return
|
|
162
|
+
if (!args.room_id) return validationError("room_id is required");
|
|
163
|
+
if (args.dry_run) return dryRunResult("POST", `/hub/rooms/${args.room_id}/leave`);
|
|
175
164
|
await client.leaveRoom(args.room_id);
|
|
176
165
|
return { ok: true, left: args.room_id };
|
|
177
166
|
|
|
178
167
|
case "dissolve":
|
|
179
|
-
if (!args.room_id) return
|
|
168
|
+
if (!args.room_id) return validationError("room_id is required");
|
|
169
|
+
if (args.dry_run) return dryRunResult("DELETE", `/hub/rooms/${args.room_id}`);
|
|
180
170
|
await client.dissolveRoom(args.room_id);
|
|
181
171
|
return { ok: true, dissolved: args.room_id };
|
|
182
172
|
|
|
183
173
|
case "members":
|
|
184
|
-
if (!args.room_id) return
|
|
185
|
-
return await client.getRoomMembers(args.room_id);
|
|
174
|
+
if (!args.room_id) return validationError("room_id is required");
|
|
175
|
+
return { members: await client.getRoomMembers(args.room_id) };
|
|
186
176
|
|
|
187
177
|
case "invite":
|
|
188
|
-
if (!args.room_id || !args.agent_id) return
|
|
178
|
+
if (!args.room_id || !args.agent_id) return validationError("room_id and agent_id are required");
|
|
179
|
+
if (args.dry_run) return dryRunResult("POST", `/hub/rooms/${args.room_id}/members`, { agent_id: args.agent_id, can_send: args.can_send, can_invite: args.can_invite });
|
|
189
180
|
await client.inviteToRoom(args.room_id, args.agent_id, {
|
|
190
181
|
can_send: args.can_send,
|
|
191
182
|
can_invite: args.can_invite,
|
|
@@ -193,22 +184,26 @@ export function createRoomsTool() {
|
|
|
193
184
|
return { ok: true, invited: args.agent_id, room: args.room_id };
|
|
194
185
|
|
|
195
186
|
case "remove_member":
|
|
196
|
-
if (!args.room_id || !args.agent_id) return
|
|
187
|
+
if (!args.room_id || !args.agent_id) return validationError("room_id and agent_id are required");
|
|
188
|
+
if (args.dry_run) return dryRunResult("DELETE", `/hub/rooms/${args.room_id}/members/${args.agent_id}`);
|
|
197
189
|
await client.removeMember(args.room_id, args.agent_id);
|
|
198
190
|
return { ok: true, removed: args.agent_id, room: args.room_id };
|
|
199
191
|
|
|
200
192
|
case "promote":
|
|
201
|
-
if (!args.room_id || !args.agent_id) return
|
|
193
|
+
if (!args.room_id || !args.agent_id) return validationError("room_id and agent_id are required");
|
|
194
|
+
if (args.dry_run) return dryRunResult("POST", `/hub/rooms/${args.room_id}/promote`, { agent_id: args.agent_id, role: args.role || "admin" });
|
|
202
195
|
await client.promoteMember(args.room_id, args.agent_id, args.role || "admin");
|
|
203
196
|
return { ok: true, promoted: args.agent_id, role: args.role || "admin", room: args.room_id };
|
|
204
197
|
|
|
205
198
|
case "transfer":
|
|
206
|
-
if (!args.room_id || !args.agent_id) return
|
|
199
|
+
if (!args.room_id || !args.agent_id) return validationError("room_id and agent_id are required");
|
|
200
|
+
if (args.dry_run) return dryRunResult("POST", `/hub/rooms/${args.room_id}/transfer`, { new_owner_id: args.agent_id });
|
|
207
201
|
await client.transferOwnership(args.room_id, args.agent_id);
|
|
208
202
|
return { ok: true, new_owner: args.agent_id, room: args.room_id };
|
|
209
203
|
|
|
210
204
|
case "permissions":
|
|
211
|
-
if (!args.room_id || !args.agent_id) return
|
|
205
|
+
if (!args.room_id || !args.agent_id) return validationError("room_id and agent_id are required");
|
|
206
|
+
if (args.dry_run) return dryRunResult("POST", `/hub/rooms/${args.room_id}/permissions`, { agent_id: args.agent_id, can_send: args.can_send, can_invite: args.can_invite });
|
|
212
207
|
await client.setMemberPermissions(args.room_id, args.agent_id, {
|
|
213
208
|
can_send: args.can_send,
|
|
214
209
|
can_invite: args.can_invite,
|
|
@@ -216,16 +211,15 @@ export function createRoomsTool() {
|
|
|
216
211
|
return { ok: true, agent: args.agent_id, room: args.room_id };
|
|
217
212
|
|
|
218
213
|
case "mute":
|
|
219
|
-
if (!args.room_id) return
|
|
214
|
+
if (!args.room_id) return validationError("room_id is required");
|
|
215
|
+
if (args.dry_run) return dryRunResult("POST", `/hub/rooms/${args.room_id}/mute`, { muted: args.muted ?? true });
|
|
220
216
|
await client.muteRoom(args.room_id, args.muted ?? true);
|
|
221
217
|
return { ok: true, room: args.room_id, muted: args.muted ?? true };
|
|
222
218
|
|
|
223
219
|
default:
|
|
224
|
-
return
|
|
220
|
+
return validationError(`Unknown action: ${args.action}`);
|
|
225
221
|
}
|
|
226
|
-
}
|
|
227
|
-
return { error: `Room action failed: ${err.message}` };
|
|
228
|
-
}
|
|
222
|
+
});
|
|
229
223
|
},
|
|
230
224
|
};
|
|
231
225
|
}
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* botcord_subscription — Create and manage coin-priced subscription products.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
isAccountConfigured,
|
|
8
|
-
} from "../config.js";
|
|
9
|
-
import { BotCordClient } from "../client.js";
|
|
10
|
-
import { attachTokenPersistence } from "../credentials.js";
|
|
11
|
-
import { getConfig as getAppConfig } from "../runtime.js";
|
|
12
|
-
import { formatCoinAmount } from "./coin-format.js";
|
|
4
|
+
import { withClient } from "./with-client.js";
|
|
5
|
+
import { validationError, dryRunResult } from "./tool-result.js";
|
|
6
|
+
import { formatCoinAmount, parseCoinToMinor } from "./coin-format.js";
|
|
13
7
|
|
|
14
8
|
function formatProduct(product: any): string {
|
|
15
9
|
return [
|
|
@@ -98,14 +92,14 @@ export function createSubscriptionTool() {
|
|
|
98
92
|
type: "string" as const,
|
|
99
93
|
description: "Room rule/instructions — for create_subscription_room or bind_room_to_product",
|
|
100
94
|
},
|
|
101
|
-
|
|
95
|
+
amount: {
|
|
102
96
|
type: "string" as const,
|
|
103
|
-
description: "Price in
|
|
97
|
+
description: "Price in COIN (supports up to 2 decimals, e.g. \"10\" or \"9.50\") — for create_product",
|
|
104
98
|
},
|
|
105
99
|
billing_interval: {
|
|
106
100
|
type: "string" as const,
|
|
107
|
-
enum: ["week", "month"],
|
|
108
|
-
description: "Billing interval — for create_product",
|
|
101
|
+
enum: ["week", "month", "once"],
|
|
102
|
+
description: "Billing interval — for create_product. Use \"once\" for one-time payment (no recurring charges)",
|
|
109
103
|
},
|
|
110
104
|
asset_code: {
|
|
111
105
|
type: "string" as const,
|
|
@@ -127,33 +121,27 @@ export function createSubscriptionTool() {
|
|
|
127
121
|
type: "number" as const,
|
|
128
122
|
description: "Slow mode interval in seconds — for create_subscription_room or bind_room_to_product",
|
|
129
123
|
},
|
|
124
|
+
dry_run: {
|
|
125
|
+
type: "boolean" as const,
|
|
126
|
+
description: "Preview the request without executing. Returns the API call that would be made.",
|
|
127
|
+
},
|
|
130
128
|
},
|
|
131
129
|
required: ["action"],
|
|
132
130
|
},
|
|
133
131
|
execute: async (toolCallId: any, args: any, signal?: any, onUpdate?: any) => {
|
|
134
|
-
|
|
135
|
-
if (!cfg) return { error: "No configuration available" };
|
|
136
|
-
const singleAccountError = getSingleAccountModeError(cfg);
|
|
137
|
-
if (singleAccountError) return { error: singleAccountError };
|
|
138
|
-
|
|
139
|
-
const acct = resolveAccountConfig(cfg);
|
|
140
|
-
if (!isAccountConfigured(acct)) {
|
|
141
|
-
return { error: "BotCord is not configured." };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const client = new BotCordClient(acct);
|
|
145
|
-
attachTokenPersistence(client, acct);
|
|
146
|
-
|
|
147
|
-
try {
|
|
132
|
+
return withClient(async (client) => {
|
|
148
133
|
switch (args.action) {
|
|
149
134
|
case "create_product": {
|
|
150
|
-
if (!args.name) return
|
|
151
|
-
if (!args.
|
|
152
|
-
if (!args.billing_interval) return
|
|
135
|
+
if (!args.name) return validationError("name is required");
|
|
136
|
+
if (!args.amount) return validationError("amount is required");
|
|
137
|
+
if (!args.billing_interval) return validationError("billing_interval is required");
|
|
138
|
+
const amountMinor = parseCoinToMinor(args.amount);
|
|
139
|
+
if (amountMinor === null) return validationError("amount must be a valid number (e.g. \"10\" or \"9.50\")");
|
|
140
|
+
if (args.dry_run) return dryRunResult("POST", "/subscriptions/products", { name: args.name, amount_minor: amountMinor, billing_interval: args.billing_interval });
|
|
153
141
|
const product = await client.createSubscriptionProduct({
|
|
154
142
|
name: args.name,
|
|
155
143
|
description: args.description,
|
|
156
|
-
amount_minor:
|
|
144
|
+
amount_minor: amountMinor,
|
|
157
145
|
billing_interval: args.billing_interval,
|
|
158
146
|
asset_code: args.asset_code,
|
|
159
147
|
});
|
|
@@ -171,14 +159,16 @@ export function createSubscriptionTool() {
|
|
|
171
159
|
}
|
|
172
160
|
|
|
173
161
|
case "archive_product": {
|
|
174
|
-
if (!args.product_id) return
|
|
162
|
+
if (!args.product_id) return validationError("product_id is required");
|
|
163
|
+
if (args.dry_run) return dryRunResult("POST", `/subscriptions/products/${args.product_id}/archive`);
|
|
175
164
|
const product = await client.archiveSubscriptionProduct(args.product_id);
|
|
176
165
|
return { result: formatProduct(product), data: product };
|
|
177
166
|
}
|
|
178
167
|
|
|
179
168
|
case "create_subscription_room": {
|
|
180
|
-
if (!args.product_id) return
|
|
181
|
-
if (!args.name) return
|
|
169
|
+
if (!args.product_id) return validationError("product_id is required");
|
|
170
|
+
if (!args.name) return validationError("name is required");
|
|
171
|
+
if (args.dry_run) return dryRunResult("POST", "/hub/rooms", { name: args.name, description: args.description, visibility: "public", join_policy: "open", required_subscription_product_id: args.product_id });
|
|
182
172
|
const room = await client.createRoom({
|
|
183
173
|
name: args.name,
|
|
184
174
|
description: args.description,
|
|
@@ -198,8 +188,9 @@ export function createSubscriptionTool() {
|
|
|
198
188
|
}
|
|
199
189
|
|
|
200
190
|
case "bind_room_to_product": {
|
|
201
|
-
if (!args.room_id) return
|
|
202
|
-
if (!args.product_id) return
|
|
191
|
+
if (!args.room_id) return validationError("room_id is required");
|
|
192
|
+
if (!args.product_id) return validationError("product_id is required");
|
|
193
|
+
if (args.dry_run) return dryRunResult("PATCH", `/hub/rooms/${args.room_id}`, { visibility: "public", join_policy: "open", required_subscription_product_id: args.product_id });
|
|
203
194
|
const room = await client.updateRoom(args.room_id, {
|
|
204
195
|
name: args.name,
|
|
205
196
|
description: args.description,
|
|
@@ -219,7 +210,8 @@ export function createSubscriptionTool() {
|
|
|
219
210
|
}
|
|
220
211
|
|
|
221
212
|
case "subscribe": {
|
|
222
|
-
if (!args.product_id) return
|
|
213
|
+
if (!args.product_id) return validationError("product_id is required");
|
|
214
|
+
if (args.dry_run) return dryRunResult("POST", `/subscriptions/products/${args.product_id}/subscribe`);
|
|
223
215
|
const subscription = await client.subscribeToProduct(args.product_id, args.idempotency_key);
|
|
224
216
|
return { result: formatSubscription(subscription), data: subscription };
|
|
225
217
|
}
|
|
@@ -230,23 +222,22 @@ export function createSubscriptionTool() {
|
|
|
230
222
|
}
|
|
231
223
|
|
|
232
224
|
case "list_subscribers": {
|
|
233
|
-
if (!args.product_id) return
|
|
225
|
+
if (!args.product_id) return validationError("product_id is required");
|
|
234
226
|
const subscriptions = await client.listProductSubscribers(args.product_id);
|
|
235
227
|
return { result: formatSubscriptionList(subscriptions), data: subscriptions };
|
|
236
228
|
}
|
|
237
229
|
|
|
238
230
|
case "cancel": {
|
|
239
|
-
if (!args.subscription_id) return
|
|
231
|
+
if (!args.subscription_id) return validationError("subscription_id is required");
|
|
232
|
+
if (args.dry_run) return dryRunResult("POST", `/subscriptions/${args.subscription_id}/cancel`);
|
|
240
233
|
const subscription = await client.cancelSubscription(args.subscription_id);
|
|
241
234
|
return { result: formatSubscription(subscription), data: subscription };
|
|
242
235
|
}
|
|
243
236
|
|
|
244
237
|
default:
|
|
245
|
-
return
|
|
238
|
+
return validationError(`Unknown action: ${args.action}`);
|
|
246
239
|
}
|
|
247
|
-
}
|
|
248
|
-
return { error: `Subscription action failed: ${err.message}` };
|
|
249
|
-
}
|
|
240
|
+
});
|
|
250
241
|
},
|
|
251
242
|
};
|
|
252
243
|
}
|
package/src/tools/tool-result.ts
CHANGED
|
@@ -28,7 +28,8 @@ export interface DryRunRequest {
|
|
|
28
28
|
method: string;
|
|
29
29
|
path: string;
|
|
30
30
|
body?: unknown;
|
|
31
|
-
query?: Record<string, string>;
|
|
31
|
+
query?: Record<string, string | string[]>;
|
|
32
|
+
note?: string;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export type DryRunResult = { ok: true; dry_run: true; request: DryRunRequest };
|
|
@@ -60,11 +61,17 @@ export function apiError(code: string, message: string, hint?: string): ToolFail
|
|
|
60
61
|
return fail("api", code, message, hint);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
export function dryRunResult(method: string, path: string, body?: unknown, query?: Record<string, string
|
|
64
|
+
export function dryRunResult(method: string, path: string, body?: unknown, options?: { query?: Record<string, string | string[]>; note?: string }): DryRunResult {
|
|
64
65
|
return {
|
|
65
66
|
ok: true,
|
|
66
67
|
dry_run: true,
|
|
67
|
-
request: {
|
|
68
|
+
request: {
|
|
69
|
+
method,
|
|
70
|
+
path,
|
|
71
|
+
...(body !== undefined ? { body } : {}),
|
|
72
|
+
...(options?.query ? { query: options.query } : {}),
|
|
73
|
+
...(options?.note ? { note: options.note } : {}),
|
|
74
|
+
},
|
|
68
75
|
};
|
|
69
76
|
}
|
|
70
77
|
|
package/src/tools/topics.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* botcord_topics — Topic lifecycle management within rooms.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
resolveAccountConfig,
|
|
7
|
-
isAccountConfigured,
|
|
8
|
-
} from "../config.js";
|
|
9
|
-
import { BotCordClient } from "../client.js";
|
|
10
|
-
import { attachTokenPersistence } from "../credentials.js";
|
|
11
|
-
import { getConfig as getAppConfig } from "../runtime.js";
|
|
4
|
+
import { withClient } from "./with-client.js";
|
|
5
|
+
import { validationError, dryRunResult } from "./tool-result.js";
|
|
12
6
|
|
|
13
7
|
export function createTopicsTool() {
|
|
14
8
|
return {
|
|
@@ -50,27 +44,19 @@ export function createTopicsTool() {
|
|
|
50
44
|
enum: ["open", "completed", "failed", "expired"],
|
|
51
45
|
description: "Topic status — for list (filter) or update (transition)",
|
|
52
46
|
},
|
|
47
|
+
dry_run: {
|
|
48
|
+
type: "boolean" as const,
|
|
49
|
+
description: "Preview the request without executing. Returns the API call that would be made.",
|
|
50
|
+
},
|
|
53
51
|
},
|
|
54
52
|
required: ["action", "room_id"],
|
|
55
53
|
},
|
|
56
54
|
execute: async (toolCallId: any, args: any, signal?: any, onUpdate?: any) => {
|
|
57
|
-
|
|
58
|
-
if (!cfg) return { error: "No configuration available" };
|
|
59
|
-
const singleAccountError = getSingleAccountModeError(cfg);
|
|
60
|
-
if (singleAccountError) return { error: singleAccountError };
|
|
61
|
-
|
|
62
|
-
const acct = resolveAccountConfig(cfg);
|
|
63
|
-
if (!isAccountConfigured(acct)) {
|
|
64
|
-
return { error: "BotCord is not configured." };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const client = new BotCordClient(acct);
|
|
68
|
-
attachTokenPersistence(client, acct);
|
|
69
|
-
|
|
70
|
-
try {
|
|
55
|
+
return withClient(async (client) => {
|
|
71
56
|
switch (args.action) {
|
|
72
57
|
case "create":
|
|
73
|
-
if (!args.title) return
|
|
58
|
+
if (!args.title) return validationError("title is required");
|
|
59
|
+
if (args.dry_run) return dryRunResult("POST", `/hub/rooms/${args.room_id}/topics`, { title: args.title, description: args.description, goal: args.goal });
|
|
74
60
|
return await client.createTopic(args.room_id, {
|
|
75
61
|
title: args.title,
|
|
76
62
|
description: args.description,
|
|
@@ -78,14 +64,15 @@ export function createTopicsTool() {
|
|
|
78
64
|
});
|
|
79
65
|
|
|
80
66
|
case "list":
|
|
81
|
-
return await client.listTopics(args.room_id, args.status);
|
|
67
|
+
return { topics: await client.listTopics(args.room_id, args.status) };
|
|
82
68
|
|
|
83
69
|
case "get":
|
|
84
|
-
if (!args.topic_id) return
|
|
70
|
+
if (!args.topic_id) return validationError("topic_id is required");
|
|
85
71
|
return await client.getTopic(args.room_id, args.topic_id);
|
|
86
72
|
|
|
87
73
|
case "update":
|
|
88
|
-
if (!args.topic_id) return
|
|
74
|
+
if (!args.topic_id) return validationError("topic_id is required");
|
|
75
|
+
if (args.dry_run) return dryRunResult("PATCH", `/hub/rooms/${args.room_id}/topics/${args.topic_id}`, { title: args.title, status: args.status, goal: args.goal });
|
|
89
76
|
return await client.updateTopic(args.room_id, args.topic_id, {
|
|
90
77
|
title: args.title,
|
|
91
78
|
description: args.description,
|
|
@@ -94,16 +81,15 @@ export function createTopicsTool() {
|
|
|
94
81
|
});
|
|
95
82
|
|
|
96
83
|
case "delete":
|
|
97
|
-
if (!args.topic_id) return
|
|
84
|
+
if (!args.topic_id) return validationError("topic_id is required");
|
|
85
|
+
if (args.dry_run) return dryRunResult("DELETE", `/hub/rooms/${args.room_id}/topics/${args.topic_id}`);
|
|
98
86
|
await client.deleteTopic(args.room_id, args.topic_id);
|
|
99
87
|
return { ok: true, deleted: args.topic_id, room: args.room_id };
|
|
100
88
|
|
|
101
89
|
default:
|
|
102
|
-
return
|
|
90
|
+
return validationError(`Unknown action: ${args.action}`);
|
|
103
91
|
}
|
|
104
|
-
}
|
|
105
|
-
return { error: `Topic action failed: ${err.message}` };
|
|
106
|
-
}
|
|
92
|
+
});
|
|
107
93
|
},
|
|
108
94
|
};
|
|
109
95
|
}
|