@botschat/botschat 0.1.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.
@@ -0,0 +1,312 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * botschat-setup — Interactive CLI to connect your OpenClaw to BotsChat.
5
+ *
6
+ * Usage:
7
+ * botschat-setup # Interactive mode
8
+ * botschat-setup --url https://console.botschat.app --token bc_pat_xxx # Non-interactive
9
+ * botschat-setup --url https://console.botschat.app --email me@x.com --password xxx
10
+ */
11
+
12
+ import { execFileSync } from "node:child_process";
13
+ import { createInterface } from "node:readline";
14
+
15
+ const DEFAULT_URL = "https://console.botschat.app";
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Helpers
19
+ // ---------------------------------------------------------------------------
20
+
21
+ function parseArgs(argv) {
22
+ const args = {};
23
+ for (let i = 2; i < argv.length; i++) {
24
+ const arg = argv[i];
25
+ if (arg.startsWith("--")) {
26
+ const key = arg.slice(2);
27
+ const next = argv[i + 1];
28
+ if (next && !next.startsWith("--")) {
29
+ args[key] = next;
30
+ i++;
31
+ } else {
32
+ args[key] = true;
33
+ }
34
+ }
35
+ }
36
+ return args;
37
+ }
38
+
39
+ /** Check if URL is loopback (localhost / 127.x) */
40
+ function isLoopbackUrl(url) {
41
+ try {
42
+ const u = new URL(url);
43
+ return u.hostname === "localhost" || u.hostname.startsWith("127.");
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+
49
+ function prompt(rl, question, defaultValue) {
50
+ return new Promise((resolve) => {
51
+ const suffix = defaultValue ? ` [${defaultValue}]` : "";
52
+ rl.question(` ${question}${suffix}: `, (answer) => {
53
+ resolve(answer.trim() || defaultValue || "");
54
+ });
55
+ });
56
+ }
57
+
58
+ function promptPassword(rl, question) {
59
+ return new Promise((resolve) => {
60
+ // Use raw mode to hide password input
61
+ process.stdout.write(` ${question}: `);
62
+ const stdin = process.stdin;
63
+ const wasRaw = stdin.isRaw;
64
+ if (stdin.setRawMode) stdin.setRawMode(true);
65
+ stdin.resume();
66
+
67
+ let password = "";
68
+ const onData = (ch) => {
69
+ const c = ch.toString("utf8");
70
+ if (c === "\n" || c === "\r" || c === "\u0004") {
71
+ if (stdin.setRawMode) stdin.setRawMode(wasRaw);
72
+ stdin.removeListener("data", onData);
73
+ process.stdout.write("\n");
74
+ resolve(password);
75
+ } else if (c === "\u0003") {
76
+ // Ctrl+C
77
+ process.exit(1);
78
+ } else if (c === "\u007f" || c === "\b") {
79
+ // Backspace
80
+ if (password.length > 0) {
81
+ password = password.slice(0, -1);
82
+ process.stdout.write("\b \b");
83
+ }
84
+ } else {
85
+ password += c;
86
+ process.stdout.write("*");
87
+ }
88
+ };
89
+ stdin.on("data", onData);
90
+ });
91
+ }
92
+
93
+ function runOpenclaw(args) {
94
+ const PATH = process.env.PATH || "";
95
+ const env = { ...process.env, PATH: `/opt/homebrew/bin:${PATH}` };
96
+ try {
97
+ execFileSync("openclaw", args, { env, stdio: "pipe" });
98
+ return true;
99
+ } catch {
100
+ return false;
101
+ }
102
+ }
103
+
104
+ async function checkConnection(baseUrl, token, maxWait = 15000) {
105
+ const start = Date.now();
106
+ while (Date.now() - start < maxWait) {
107
+ try {
108
+ const resp = await fetch(`${baseUrl}/api/setup/status`, {
109
+ headers: { Authorization: `Bearer ${token}` },
110
+ });
111
+ if (resp.ok) {
112
+ const data = await resp.json();
113
+ if (data.connected) return true;
114
+ }
115
+ } catch { /* retry */ }
116
+ await new Promise((r) => setTimeout(r, 2000));
117
+ }
118
+ return false;
119
+ }
120
+
121
+ // ---------------------------------------------------------------------------
122
+ // Main
123
+ // ---------------------------------------------------------------------------
124
+
125
+ async function main() {
126
+ const args = parseArgs(process.argv);
127
+
128
+ if (args.help || args.h) {
129
+ console.log(`
130
+ botschat-setup — Connect your OpenClaw to BotsChat
131
+
132
+ Usage:
133
+ botschat-setup Interactive setup
134
+ botschat-setup --token bc_pat_xxx Use existing token
135
+ botschat-setup --email me@x.com --password xxx Login and setup
136
+ botschat-setup --url https://console.botschat.app --token ... Custom server
137
+
138
+ Options:
139
+ --url BotsChat server URL (default: ${DEFAULT_URL})
140
+ --token Pairing token (bc_pat_xxx)
141
+ --email Email for login (creates pairing token automatically)
142
+ --password Password for login
143
+ --help Show this help
144
+ `);
145
+ process.exit(0);
146
+ }
147
+
148
+ console.log();
149
+ console.log(" BotsChat Setup");
150
+ console.log(" ─────────────────────────────────────────");
151
+ console.log();
152
+
153
+ let cloudUrl = args.url || "";
154
+ let pairingToken = args.token || "";
155
+ let jwtToken = "";
156
+
157
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
158
+
159
+ try {
160
+ // ---- Step 1: Get cloud URL ----
161
+ if (!cloudUrl) {
162
+ cloudUrl = await prompt(rl, "BotsChat URL", DEFAULT_URL);
163
+ }
164
+ // Normalize: strip trailing slash
165
+ cloudUrl = cloudUrl.replace(/\/+$/, "");
166
+
167
+ // ---- Step 2: Get pairing token (direct or via login) ----
168
+ if (!pairingToken) {
169
+ if (args.email && args.password) {
170
+ // Non-interactive login
171
+ console.log(` Logging in as ${args.email}...`);
172
+ const resp = await fetch(`${cloudUrl}/api/setup/init`, {
173
+ method: "POST",
174
+ headers: { "Content-Type": "application/json" },
175
+ body: JSON.stringify({ email: args.email, password: args.password }),
176
+ });
177
+ if (!resp.ok) {
178
+ const err = await resp.json().catch(() => ({}));
179
+ console.error(` Error: ${err.error || `HTTP ${resp.status}`}`);
180
+ process.exit(1);
181
+ }
182
+ const data = await resp.json();
183
+ pairingToken = data.pairingToken;
184
+ jwtToken = data.token;
185
+ console.log(` Authenticated as ${data.email}`);
186
+ } else {
187
+ // Ask: do you have a token, or login?
188
+ console.log(" How would you like to authenticate?");
189
+ console.log(" 1) I have a pairing token (from the BotsChat web UI)");
190
+ console.log(" 2) Login with email and password");
191
+ console.log();
192
+ const choice = await prompt(rl, "Choice", "1");
193
+
194
+ if (choice === "2") {
195
+ const email = await prompt(rl, "Email", "");
196
+ const password = await promptPassword(rl, "Password");
197
+
198
+ console.log(" Logging in...");
199
+ const resp = await fetch(`${cloudUrl}/api/setup/init`, {
200
+ method: "POST",
201
+ headers: { "Content-Type": "application/json" },
202
+ body: JSON.stringify({ email, password }),
203
+ });
204
+ if (!resp.ok) {
205
+ const err = await resp.json().catch(() => ({}));
206
+ console.error(` Error: ${err.error || `HTTP ${resp.status}`}`);
207
+ process.exit(1);
208
+ }
209
+ const data = await resp.json();
210
+ pairingToken = data.pairingToken;
211
+ jwtToken = data.token;
212
+ console.log(` Authenticated as ${data.email}`);
213
+ } else {
214
+ pairingToken = await prompt(rl, "Pairing token (bc_pat_...)", "");
215
+ if (!pairingToken) {
216
+ console.error(" Error: Pairing token is required");
217
+ process.exit(1);
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ // ---- Step 2.5: Smart URL resolution — prefer the API's recommendation ----
224
+ // The /api/setup/init response's cloudUrl is resolved by the backend.
225
+ // But if we logged in, also check the cloudUrlWarning.
226
+ // If the URL is loopback and user hasn't explicitly chosen it, warn.
227
+ if (isLoopbackUrl(cloudUrl)) {
228
+ console.log();
229
+ console.log(" \x1b[33m⚠ Warning:\x1b[0m The cloud URL is \x1b[1m" + cloudUrl + "\x1b[0m (localhost).");
230
+ console.log(" This only works if OpenClaw is on the same machine.");
231
+ console.log(" If OpenClaw is on another host, use a LAN IP instead,");
232
+ console.log(" e.g. http://192.168.x.x:8787 or http://10.x.x.x:8787");
233
+ console.log();
234
+ const override = await prompt(rl, "Cloud URL (press Enter to keep, or type new URL)", cloudUrl);
235
+ if (override && override !== cloudUrl) {
236
+ cloudUrl = override.replace(/\/+$/, "");
237
+ }
238
+ }
239
+
240
+ // If the API returned a cloudUrlWarning (e.g. via login), the URL was
241
+ // already chosen in step 2. Try to resolve a better URL via /api/setup/cloud-url.
242
+ try {
243
+ const cuResp = await fetch(`${cloudUrl}/api/setup/cloud-url`);
244
+ if (cuResp.ok) {
245
+ const cuData = await cuResp.json();
246
+ if (cuData.cloudUrl && cuData.cloudUrl !== cloudUrl && !isLoopbackUrl(cuData.cloudUrl)) {
247
+ console.log(` Server recommends: ${cuData.cloudUrl}`);
248
+ const useRecommended = await prompt(rl, `Use ${cuData.cloudUrl} instead? [Y/n]`, "Y");
249
+ if (!useRecommended || useRecommended.toLowerCase() !== "n") {
250
+ cloudUrl = cuData.cloudUrl;
251
+ }
252
+ }
253
+ }
254
+ } catch { /* ignore — we'll use what we have */ }
255
+
256
+ console.log();
257
+ console.log(" Configuring OpenClaw...");
258
+
259
+ // ---- Step 3: Write config via openclaw CLI ----
260
+ const steps = [
261
+ { label: "Setting cloud URL", args: ["config", "set", "channels.botschat.cloudUrl", cloudUrl] },
262
+ { label: "Setting pairing token", args: ["config", "set", "channels.botschat.pairingToken", pairingToken] },
263
+ { label: "Enabling channel", args: ["config", "set", "channels.botschat.enabled", "true"] },
264
+ ];
265
+
266
+ for (const step of steps) {
267
+ process.stdout.write(` ${step.label}...`);
268
+ const ok = runOpenclaw(step.args);
269
+ console.log(ok ? " done" : " FAILED");
270
+ if (!ok) {
271
+ console.error(" Error: Failed to run openclaw CLI. Is openclaw installed and in PATH?");
272
+ process.exit(1);
273
+ }
274
+ }
275
+
276
+ // ---- Step 4: Restart gateway ----
277
+ console.log();
278
+ process.stdout.write(" Restarting gateway...");
279
+ const restarted = runOpenclaw(["gateway", "restart"]);
280
+ console.log(restarted ? " done" : " FAILED (you may need to restart manually)");
281
+
282
+ // ---- Step 5: Verify connection ----
283
+ if (jwtToken) {
284
+ console.log();
285
+ process.stdout.write(" Verifying connection...");
286
+ const connected = await checkConnection(cloudUrl, jwtToken);
287
+ if (connected) {
288
+ console.log(" connected!");
289
+ console.log();
290
+ console.log(" Setup complete! Open your BotsChat web UI to start chatting.");
291
+ } else {
292
+ console.log(" not yet connected.");
293
+ console.log(" Check your gateway logs: openclaw gateway logs");
294
+ }
295
+ } else {
296
+ console.log();
297
+ console.log(" Configuration saved! Check connection with:");
298
+ console.log(" openclaw gateway logs");
299
+ }
300
+
301
+ console.log();
302
+ console.log(" ─────────────────────────────────────────");
303
+ console.log();
304
+ } finally {
305
+ rl.close();
306
+ }
307
+ }
308
+
309
+ main().catch((err) => {
310
+ console.error(" Error:", err.message || err);
311
+ process.exit(1);
312
+ });
@@ -0,0 +1,19 @@
1
+ import { botschatPlugin } from "./src/channel.js";
2
+ declare const plugin: {
3
+ id: string;
4
+ name: string;
5
+ description: string;
6
+ configSchema: {
7
+ safeParse: () => {
8
+ success: boolean;
9
+ };
10
+ };
11
+ register(api: {
12
+ runtime: unknown;
13
+ registerChannel: (reg: {
14
+ plugin: typeof botschatPlugin;
15
+ }) => void;
16
+ }): void;
17
+ };
18
+ export default plugin;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAMlD,QAAA,MAAM,MAAM;;;;;;;;;kBAKI;QACZ,OAAO,EAAE,OAAO,CAAC;QACjB,eAAe,EAAE,CAAC,GAAG,EAAE;YAAE,MAAM,EAAE,OAAO,cAAc,CAAA;SAAE,KAAK,IAAI,CAAC;KACnE;CAIF,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ import { botschatPlugin } from "./src/channel.js";
2
+ import { setBotsChatRuntime } from "./src/runtime.js";
3
+ // OpenClaw Plugin Definition
4
+ // This is the entry point loaded by OpenClaw's plugin system.
5
+ // It registers the BotsChat channel plugin.
6
+ const plugin = {
7
+ id: "botschat",
8
+ name: "BotsChat",
9
+ description: "Connect to BotsChat cloud chat platform",
10
+ configSchema: { safeParse: () => ({ success: true }) },
11
+ register(api) {
12
+ setBotsChatRuntime(api.runtime);
13
+ api.registerChannel({ plugin: botschatPlugin });
14
+ },
15
+ };
16
+ export default plugin;
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,6BAA6B;AAC7B,8DAA8D;AAC9D,4CAA4C;AAC5C,MAAM,MAAM,GAAG;IACb,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,yCAAyC;IACtD,YAAY,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE;IACtD,QAAQ,CAAC,GAGR;QACC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;IAClD,CAAC;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ResolvedBotsChatAccount } from "./types.js";
2
+ /** List all configured account IDs. */
3
+ export declare function listBotsChatAccountIds(cfg: unknown): string[];
4
+ /** Resolve default account ID. */
5
+ export declare function resolveDefaultBotsChatAccountId(cfg: unknown): string;
6
+ /** Resolve a single account by ID. */
7
+ export declare function resolveBotsChatAccount(cfg: unknown, accountId?: string | null): ResolvedBotsChatAccount;
8
+ /** Delete an account from config, returning the updated config. */
9
+ export declare function deleteBotsChatAccount(cfg: unknown, accountId: string): unknown;
10
+ /** Enable or disable an account, returning updated config. */
11
+ export declare function setBotsChatAccountEnabled(cfg: unknown, accountId: string, enabled: boolean): unknown;
12
+ //# sourceMappingURL=accounts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../src/accounts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAUpB,uCAAuC;AACvC,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAgB7D;AAED,kCAAkC;AAClC,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAGpE;AAED,sCAAsC;AACtC,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,uBAAuB,CA6BzB;AAED,mEAAmE;AACnE,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAsBT;AAED,8DAA8D;AAC9D,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAoBT"}
@@ -0,0 +1,103 @@
1
+ const DEFAULT_ACCOUNT_ID = "default";
2
+ /** Extract the botschat section from the full config. */
3
+ function section(cfg) {
4
+ const c = cfg;
5
+ return c?.channels?.botschat ?? {};
6
+ }
7
+ /** List all configured account IDs. */
8
+ export function listBotsChatAccountIds(cfg) {
9
+ const s = section(cfg);
10
+ const ids = [];
11
+ // Top-level counts as "default" if it has cloudUrl
12
+ if (s.cloudUrl) {
13
+ ids.push(DEFAULT_ACCOUNT_ID);
14
+ }
15
+ // Named accounts
16
+ if (s.accounts) {
17
+ for (const id of Object.keys(s.accounts)) {
18
+ if (id !== DEFAULT_ACCOUNT_ID || !s.cloudUrl) {
19
+ ids.push(id);
20
+ }
21
+ }
22
+ }
23
+ return ids.length > 0 ? ids : [DEFAULT_ACCOUNT_ID];
24
+ }
25
+ /** Resolve default account ID. */
26
+ export function resolveDefaultBotsChatAccountId(cfg) {
27
+ const ids = listBotsChatAccountIds(cfg);
28
+ return ids[0] ?? DEFAULT_ACCOUNT_ID;
29
+ }
30
+ /** Resolve a single account by ID. */
31
+ export function resolveBotsChatAccount(cfg, accountId) {
32
+ const s = section(cfg);
33
+ const id = accountId ?? resolveDefaultBotsChatAccountId(cfg);
34
+ let acct;
35
+ if (id === DEFAULT_ACCOUNT_ID || !s.accounts?.[id]) {
36
+ // Use top-level config
37
+ acct = {
38
+ enabled: s.enabled,
39
+ name: s.name,
40
+ cloudUrl: s.cloudUrl,
41
+ pairingToken: s.pairingToken,
42
+ };
43
+ }
44
+ else {
45
+ acct = s.accounts[id];
46
+ }
47
+ const cloudUrl = acct.cloudUrl ?? "";
48
+ const pairingToken = acct.pairingToken ?? "";
49
+ return {
50
+ accountId: id,
51
+ name: acct.name,
52
+ enabled: acct.enabled !== false,
53
+ configured: !!cloudUrl && !!pairingToken,
54
+ cloudUrl,
55
+ pairingToken,
56
+ config: acct,
57
+ };
58
+ }
59
+ /** Delete an account from config, returning the updated config. */
60
+ export function deleteBotsChatAccount(cfg, accountId) {
61
+ const c = cfg;
62
+ const botschat = { ...c?.channels?.botschat };
63
+ if (accountId === DEFAULT_ACCOUNT_ID) {
64
+ delete botschat.cloudUrl;
65
+ delete botschat.pairingToken;
66
+ delete botschat.name;
67
+ botschat.enabled = false;
68
+ }
69
+ else if (botschat.accounts) {
70
+ const accounts = { ...botschat.accounts };
71
+ delete accounts[accountId];
72
+ botschat.accounts = accounts;
73
+ }
74
+ return {
75
+ ...c,
76
+ channels: {
77
+ ...c.channels,
78
+ botschat,
79
+ },
80
+ };
81
+ }
82
+ /** Enable or disable an account, returning updated config. */
83
+ export function setBotsChatAccountEnabled(cfg, accountId, enabled) {
84
+ const c = cfg;
85
+ const botschat = { ...c?.channels?.botschat };
86
+ if (accountId === DEFAULT_ACCOUNT_ID) {
87
+ botschat.enabled = enabled;
88
+ }
89
+ else if (botschat.accounts) {
90
+ botschat.accounts = {
91
+ ...botschat.accounts,
92
+ [accountId]: { ...botschat.accounts[accountId], enabled },
93
+ };
94
+ }
95
+ return {
96
+ ...c,
97
+ channels: {
98
+ ...c.channels,
99
+ botschat,
100
+ },
101
+ };
102
+ }
103
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../src/accounts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,206 @@
1
+ import type { ResolvedBotsChatAccount } from "./types.js";
2
+ import { BotsChatCloudClient } from "./ws-client.js";
3
+ export declare const botschatPlugin: {
4
+ readonly id: "botschat";
5
+ readonly meta: {
6
+ readonly id: "botschat";
7
+ readonly label: "BotsChat";
8
+ readonly selectionLabel: "BotsChat (cloud)";
9
+ readonly docsPath: "/channels/botschat";
10
+ readonly docsLabel: "botschat";
11
+ readonly blurb: "Cloud-based multi-channel chat interface";
12
+ readonly order: 80;
13
+ readonly quickstartAllowFrom: false;
14
+ };
15
+ readonly capabilities: {
16
+ readonly chatTypes: string[];
17
+ readonly polls: false;
18
+ readonly reactions: false;
19
+ readonly threads: true;
20
+ readonly media: true;
21
+ };
22
+ readonly agentPrompt: {
23
+ readonly messageToolHints: () => string[];
24
+ };
25
+ readonly reload: {
26
+ readonly configPrefixes: readonly ["channels.botschat"];
27
+ };
28
+ readonly config: {
29
+ readonly listAccountIds: (cfg: unknown) => string[];
30
+ readonly resolveAccount: (cfg: unknown, accountId?: string | null) => ResolvedBotsChatAccount;
31
+ readonly defaultAccountId: (cfg: unknown) => string;
32
+ readonly setAccountEnabled: ({ cfg, accountId, enabled }: {
33
+ cfg: unknown;
34
+ accountId: string;
35
+ enabled: boolean;
36
+ }) => unknown;
37
+ readonly deleteAccount: ({ cfg, accountId }: {
38
+ cfg: unknown;
39
+ accountId: string;
40
+ }) => unknown;
41
+ readonly isConfigured: (account: ResolvedBotsChatAccount) => boolean;
42
+ readonly isEnabled: (account: ResolvedBotsChatAccount) => boolean;
43
+ readonly describeAccount: (account: ResolvedBotsChatAccount) => {
44
+ accountId: string;
45
+ name: string | undefined;
46
+ enabled: boolean;
47
+ configured: boolean;
48
+ baseUrl: string;
49
+ };
50
+ };
51
+ readonly outbound: {
52
+ readonly deliveryMode: "direct";
53
+ readonly sendText: (ctx: {
54
+ to: string;
55
+ text: string;
56
+ replyToId?: string | null;
57
+ threadId?: string | number | null;
58
+ accountId?: string | null;
59
+ }) => Promise<{
60
+ ok: boolean;
61
+ error: Error;
62
+ } | {
63
+ ok: boolean;
64
+ error?: undefined;
65
+ }>;
66
+ readonly sendMedia: (ctx: {
67
+ to: string;
68
+ text: string;
69
+ mediaUrl?: string;
70
+ accountId?: string | null;
71
+ }) => Promise<{
72
+ ok: boolean;
73
+ error: Error;
74
+ } | {
75
+ ok: boolean;
76
+ error?: undefined;
77
+ }>;
78
+ };
79
+ readonly gateway: {
80
+ readonly startAccount: (ctx: {
81
+ cfg: unknown;
82
+ accountId: string;
83
+ account: ResolvedBotsChatAccount;
84
+ runtime: unknown;
85
+ abortSignal: AbortSignal;
86
+ log?: {
87
+ info: (m: string) => void;
88
+ warn: (m: string) => void;
89
+ error: (m: string) => void;
90
+ };
91
+ getStatus: () => Record<string, unknown>;
92
+ setStatus: (s: Record<string, unknown>) => void;
93
+ }) => Promise<BotsChatCloudClient | undefined>;
94
+ readonly stopAccount: (ctx: {
95
+ accountId: string;
96
+ getStatus: () => Record<string, unknown>;
97
+ setStatus: (s: Record<string, unknown>) => void;
98
+ }) => Promise<void>;
99
+ };
100
+ readonly threading: {
101
+ readonly resolveReplyToMode: () => "all";
102
+ readonly buildToolContext: ({ context, hasRepliedRef }: {
103
+ context: {
104
+ To?: string;
105
+ MessageThreadId?: string | number;
106
+ ReplyToId?: string;
107
+ };
108
+ hasRepliedRef?: {
109
+ value: boolean;
110
+ };
111
+ }) => {
112
+ currentChannelId: string | undefined;
113
+ currentChannelProvider: string;
114
+ currentThreadTs: string | undefined;
115
+ hasRepliedRef: {
116
+ value: boolean;
117
+ } | undefined;
118
+ };
119
+ };
120
+ readonly pairing: {
121
+ readonly idLabel: "botsChatUserId";
122
+ readonly normalizeAllowEntry: (entry: string) => string;
123
+ };
124
+ readonly security: {
125
+ readonly resolveDmPolicy: (_ctx: {
126
+ account: ResolvedBotsChatAccount;
127
+ }) => {
128
+ policy: string;
129
+ allowFrom: string[];
130
+ policyPath: string;
131
+ allowFromPath: string;
132
+ approveHint: string;
133
+ };
134
+ };
135
+ readonly setup: {
136
+ readonly applyAccountConfig: ({ cfg, input }: {
137
+ cfg: unknown;
138
+ accountId: string;
139
+ input: {
140
+ url?: string;
141
+ token?: string;
142
+ name?: string;
143
+ useEnv?: boolean;
144
+ };
145
+ }) => {
146
+ channels: {
147
+ botschat: {
148
+ name?: string;
149
+ enabled: boolean;
150
+ cloudUrl: string;
151
+ pairingToken: string;
152
+ accounts?: Record<string, import("./types.js").BotsChatAccountConfig>;
153
+ };
154
+ };
155
+ };
156
+ readonly validateInput: ({ input }: {
157
+ cfg: unknown;
158
+ accountId: string;
159
+ input: {
160
+ url?: string;
161
+ token?: string;
162
+ useEnv?: boolean;
163
+ };
164
+ }) => "BotsChat requires --url (e.g., --url console.botschat.app)" | "BotsChat requires --token (pairing token from console.botschat.app)" | null;
165
+ };
166
+ readonly status: {
167
+ readonly defaultRuntime: {
168
+ readonly accountId: "default";
169
+ readonly running: false;
170
+ readonly connected: false;
171
+ readonly lastStartAt: null;
172
+ readonly lastStopAt: null;
173
+ readonly lastError: null;
174
+ };
175
+ readonly buildAccountSnapshot: ({ account, runtime }: {
176
+ account: ResolvedBotsChatAccount;
177
+ cfg: unknown;
178
+ runtime?: Record<string, unknown>;
179
+ }) => {
180
+ accountId: string;
181
+ name: string | undefined;
182
+ enabled: boolean;
183
+ configured: boolean;
184
+ baseUrl: string;
185
+ running: boolean;
186
+ connected: boolean;
187
+ lastStartAt: number;
188
+ lastStopAt: number;
189
+ lastError: string;
190
+ lastConnectedAt: number;
191
+ lastDisconnect: {} | null;
192
+ };
193
+ readonly collectStatusIssues: (accounts: Array<{
194
+ accountId: string;
195
+ lastError?: string | null;
196
+ connected?: boolean;
197
+ configured?: boolean;
198
+ }>) => {
199
+ channel: string;
200
+ accountId: string;
201
+ kind: string;
202
+ message: string;
203
+ }[];
204
+ };
205
+ };
206
+ //# sourceMappingURL=channel.d.ts.map