@tinyclaw/plugin-channel-discord 2.0.0-dev.3ab4351 → 2.0.0-dev.45251ef
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/dist/index.d.ts +7 -0
- package/dist/index.js +48 -10
- package/dist/pairing.d.ts +1 -1
- package/dist/pairing.js +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
* Prefixed to prevent collisions with web UI user IDs.
|
|
16
16
|
*/
|
|
17
17
|
import type { ChannelPlugin } from '@tinyclaw/types';
|
|
18
|
+
export interface DiscordRuntimeStatus {
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
state: 'idle' | 'disabled' | 'starting' | 'connected' | 'error' | 'stopped';
|
|
21
|
+
readyTag: string | null;
|
|
22
|
+
lastError: string | null;
|
|
23
|
+
}
|
|
24
|
+
export declare function getDiscordRuntimeStatus(): DiscordRuntimeStatus;
|
|
18
25
|
declare const discordPlugin: ChannelPlugin;
|
|
19
26
|
/** Split a string into chunks without cutting words at boundaries. */
|
|
20
27
|
export declare function splitIntoChunks(text: string, maxLength: number): string[];
|
package/dist/index.js
CHANGED
|
@@ -14,10 +14,19 @@
|
|
|
14
14
|
* userId format: "discord:<discord-user-id>"
|
|
15
15
|
* Prefixed to prevent collisions with web UI user IDs.
|
|
16
16
|
*/
|
|
17
|
-
import { Client, GatewayIntentBits, Partials, Events, } from 'discord.js';
|
|
18
17
|
import { logger } from '@tinyclaw/logger';
|
|
19
|
-
import {
|
|
18
|
+
import { Client, Events, GatewayIntentBits, Partials, } from 'discord.js';
|
|
19
|
+
import { createDiscordPairingTools, DISCORD_ENABLED_CONFIG_KEY, DISCORD_TOKEN_SECRET_KEY, } from './pairing.js';
|
|
20
20
|
let client = null;
|
|
21
|
+
const runtimeStatus = {
|
|
22
|
+
enabled: false,
|
|
23
|
+
state: 'idle',
|
|
24
|
+
readyTag: null,
|
|
25
|
+
lastError: null,
|
|
26
|
+
};
|
|
27
|
+
export function getDiscordRuntimeStatus() {
|
|
28
|
+
return { ...runtimeStatus };
|
|
29
|
+
}
|
|
21
30
|
const discordPlugin = {
|
|
22
31
|
id: '@tinyclaw/plugin-channel-discord',
|
|
23
32
|
name: 'Discord',
|
|
@@ -30,15 +39,25 @@ const discordPlugin = {
|
|
|
30
39
|
},
|
|
31
40
|
async start(context) {
|
|
32
41
|
const isEnabled = context.configManager.get(DISCORD_ENABLED_CONFIG_KEY);
|
|
42
|
+
runtimeStatus.enabled = Boolean(isEnabled);
|
|
33
43
|
if (!isEnabled) {
|
|
44
|
+
runtimeStatus.state = 'disabled';
|
|
45
|
+
runtimeStatus.readyTag = null;
|
|
46
|
+
runtimeStatus.lastError = null;
|
|
34
47
|
logger.info('Discord plugin: not enabled — run pairing to enable');
|
|
35
48
|
return;
|
|
36
49
|
}
|
|
37
50
|
const token = await context.secrets.retrieve(DISCORD_TOKEN_SECRET_KEY);
|
|
38
51
|
if (!token) {
|
|
52
|
+
runtimeStatus.state = 'error';
|
|
53
|
+
runtimeStatus.readyTag = null;
|
|
54
|
+
runtimeStatus.lastError = 'Discord bot token not found in secrets';
|
|
39
55
|
logger.warn('Discord plugin: enabled but no token found — re-pair to fix');
|
|
40
56
|
return;
|
|
41
57
|
}
|
|
58
|
+
runtimeStatus.state = 'starting';
|
|
59
|
+
runtimeStatus.readyTag = null;
|
|
60
|
+
runtimeStatus.lastError = null;
|
|
42
61
|
client = new Client({
|
|
43
62
|
intents: [
|
|
44
63
|
GatewayIntentBits.Guilds,
|
|
@@ -49,23 +68,28 @@ const discordPlugin = {
|
|
|
49
68
|
partials: [Partials.Channel],
|
|
50
69
|
});
|
|
51
70
|
client.once(Events.ClientReady, (readyClient) => {
|
|
71
|
+
runtimeStatus.state = 'connected';
|
|
72
|
+
runtimeStatus.readyTag = readyClient.user.tag;
|
|
73
|
+
runtimeStatus.lastError = null;
|
|
52
74
|
logger.info(`Discord bot ready: ${readyClient.user.tag}`);
|
|
53
75
|
});
|
|
76
|
+
client.on(Events.Error, (error) => {
|
|
77
|
+
runtimeStatus.state = 'error';
|
|
78
|
+
runtimeStatus.readyTag = null;
|
|
79
|
+
runtimeStatus.lastError = error.message;
|
|
80
|
+
logger.error('Discord plugin: client error', error);
|
|
81
|
+
});
|
|
54
82
|
client.on(Events.MessageCreate, async (msg) => {
|
|
55
83
|
// Ignore messages from bots (including self)
|
|
56
84
|
if (msg.author.bot)
|
|
57
85
|
return;
|
|
58
86
|
const isDM = msg.channel.isDMBased();
|
|
59
|
-
const isMention = client?.user
|
|
60
|
-
? msg.mentions.users.has(client.user.id)
|
|
61
|
-
: false;
|
|
87
|
+
const isMention = client?.user ? msg.mentions.users.has(client.user.id) : false;
|
|
62
88
|
// Only respond to DMs or @mentions
|
|
63
89
|
if (!isDM && !isMention)
|
|
64
90
|
return;
|
|
65
91
|
// Strip @mention tokens from guild messages
|
|
66
|
-
const rawContent = msg.content
|
|
67
|
-
.replace(/<@!?[\d]+>/g, '')
|
|
68
|
-
.trim();
|
|
92
|
+
const rawContent = msg.content.replace(/<@!?[\d]+>/g, '').trim();
|
|
69
93
|
if (!rawContent)
|
|
70
94
|
return;
|
|
71
95
|
// Prefix userId to isolate Discord sessions from web UI sessions
|
|
@@ -98,8 +122,20 @@ const discordPlugin = {
|
|
|
98
122
|
}
|
|
99
123
|
}
|
|
100
124
|
});
|
|
101
|
-
|
|
102
|
-
|
|
125
|
+
try {
|
|
126
|
+
await client.login(token);
|
|
127
|
+
logger.info('Discord bot connected');
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
runtimeStatus.state = 'error';
|
|
131
|
+
runtimeStatus.readyTag = null;
|
|
132
|
+
runtimeStatus.lastError = error instanceof Error ? error.message : String(error);
|
|
133
|
+
if (client) {
|
|
134
|
+
client.destroy();
|
|
135
|
+
client = null;
|
|
136
|
+
}
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
103
139
|
},
|
|
104
140
|
async sendToUser(userId, message) {
|
|
105
141
|
if (!client) {
|
|
@@ -135,6 +171,8 @@ const discordPlugin = {
|
|
|
135
171
|
client = null;
|
|
136
172
|
logger.info('Discord bot disconnected');
|
|
137
173
|
}
|
|
174
|
+
runtimeStatus.state = runtimeStatus.enabled ? 'stopped' : 'disabled';
|
|
175
|
+
runtimeStatus.readyTag = null;
|
|
138
176
|
},
|
|
139
177
|
};
|
|
140
178
|
/** Split a string into chunks without cutting words at boundaries. */
|
package/dist/pairing.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* These tools are injected into the agent's tool list at boot so the agent
|
|
10
10
|
* can invoke them conversationally when a user asks to connect Discord.
|
|
11
11
|
*/
|
|
12
|
-
import type {
|
|
12
|
+
import type { ConfigManagerInterface, SecretsManagerInterface, Tool } from '@tinyclaw/types';
|
|
13
13
|
/** Secret key for the Discord bot token. */
|
|
14
14
|
export declare const DISCORD_TOKEN_SECRET_KEY: string;
|
|
15
15
|
/** Config key for the enabled flag. */
|
package/dist/pairing.js
CHANGED
|
@@ -21,6 +21,7 @@ export function createDiscordPairingTools(secrets, configManager) {
|
|
|
21
21
|
{
|
|
22
22
|
name: 'discord_pair',
|
|
23
23
|
description: 'Pair Tiny Claw with a Discord bot. ' +
|
|
24
|
+
'If the user has not provided a bot token yet, first walk them through creating one in the Discord Developer Portal and ask them to paste it here. ' +
|
|
24
25
|
'Stores the bot token securely and enables the Discord channel plugin. ' +
|
|
25
26
|
'After pairing, call tinyclaw_restart to connect the bot. ' +
|
|
26
27
|
'To get a token: go to https://discord.com/developers/applications, ' +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinyclaw/plugin-channel-discord",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.45251ef",
|
|
4
4
|
"description": "Discord channel plugin for Tiny Claw",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"author": "Waren Gonzaga",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"build": "tsc -p tsconfig.json"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@tinyclaw/logger": "
|
|
36
|
-
"@tinyclaw/types": "
|
|
35
|
+
"@tinyclaw/logger": "2.0.0",
|
|
36
|
+
"@tinyclaw/types": "2.0.0",
|
|
37
37
|
"discord.js": "^14.0.0"
|
|
38
38
|
}
|
|
39
39
|
}
|