verbalcoding 0.2.3 → 0.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/app-node/discord_text.test.mjs +14 -0
- package/app-node/main.mjs +15 -9
- package/docs/CONFIGURATION.md +6 -0
- package/docs/FRESH_INSTALL.md +8 -0
- package/docs/USAGE.md +7 -0
- package/docs/i18n/CONFIGURATION.ko.md +6 -0
- package/docs/i18n/FRESH_INSTALL.ko.md +8 -0
- package/docs/i18n/USAGE.ko.md +7 -0
- package/package.json +1 -1
|
@@ -8,6 +8,20 @@ test('splitDiscordMessage chunks long text for Discord', () => {
|
|
|
8
8
|
assert.deepEqual(chunks.map(c => c.length), [1900, 1900, 201]);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
+
test('sendDiscordText returns false without fetching when transcript channel id is missing', async () => {
|
|
12
|
+
const warnings = [];
|
|
13
|
+
let fetched = false;
|
|
14
|
+
const delivered = await sendDiscordText({
|
|
15
|
+
channelId: '',
|
|
16
|
+
text: 'restart complete',
|
|
17
|
+
client: { channels: { fetch: async () => { fetched = true; } } },
|
|
18
|
+
warn: (...args) => warnings.push(args.join(' ')),
|
|
19
|
+
});
|
|
20
|
+
assert.equal(delivered, false);
|
|
21
|
+
assert.equal(fetched, false);
|
|
22
|
+
assert.match(warnings.join('\n'), /missing transcript channel id/);
|
|
23
|
+
});
|
|
24
|
+
|
|
11
25
|
test('sendDiscordText returns false when target is not text based', async () => {
|
|
12
26
|
const warnings = [];
|
|
13
27
|
const delivered = await sendDiscordText({
|
package/app-node/main.mjs
CHANGED
|
@@ -166,7 +166,7 @@ const settings = {
|
|
|
166
166
|
token: process.env.DISCORD_BOT_TOKEN || process.env.DISCORD_TOKEN,
|
|
167
167
|
allowedUsers: new Set((process.env.DISCORD_ALLOWED_USERS || '').split(/[;,]/).map(s => s.trim()).filter(Boolean)),
|
|
168
168
|
autoJoinVoiceChannels: (process.env.AUTO_JOIN_VOICE_CHANNELS || '일반,General,general').split(',').map(s => s.trim().toLowerCase()).filter(Boolean),
|
|
169
|
-
transcriptChannelId: (process.env.TRANSCRIPT_CHANNEL_ID || '
|
|
169
|
+
transcriptChannelId: (process.env.TRANSCRIPT_CHANNEL_ID || '').trim(),
|
|
170
170
|
whisperBin: process.env.WHISPER_CPP_BIN || 'whisper-cli',
|
|
171
171
|
whisperModel: process.env.WHISPER_CPP_MODEL || path.join(ROOT, 'models', 'ggml-small-q5_1.bin'),
|
|
172
172
|
whisperLanguage: process.env.WHISPER_CPP_LANGUAGE || process.env.STT_LANGUAGE || 'ko',
|
|
@@ -1402,26 +1402,32 @@ async function connectTo(channel) {
|
|
|
1402
1402
|
selfDeaf: false,
|
|
1403
1403
|
selfMute: false,
|
|
1404
1404
|
});
|
|
1405
|
-
connection
|
|
1406
|
-
|
|
1407
|
-
|
|
1405
|
+
const voiceConnection = connection;
|
|
1406
|
+
voiceConnection.subscribe(player);
|
|
1407
|
+
voiceConnection.on('error', e => warn('voice connection error', e?.stack || e));
|
|
1408
|
+
voiceConnection.on('stateChange', async (oldState, newState) => {
|
|
1408
1409
|
log('voice connection state', oldState.status, '->', newState.status);
|
|
1410
|
+
if (connection !== voiceConnection) {
|
|
1411
|
+
log('ignore stale voice connection state', oldState.status, '->', newState.status);
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1409
1414
|
if (newState.status === VoiceConnectionStatus.Disconnected) {
|
|
1410
1415
|
try {
|
|
1411
1416
|
await Promise.race([
|
|
1412
|
-
entersState(
|
|
1413
|
-
entersState(
|
|
1417
|
+
entersState(voiceConnection, VoiceConnectionStatus.Signalling, 5000),
|
|
1418
|
+
entersState(voiceConnection, VoiceConnectionStatus.Connecting, 5000),
|
|
1414
1419
|
]);
|
|
1415
1420
|
} catch (e) {
|
|
1421
|
+
if (connection !== voiceConnection) return;
|
|
1416
1422
|
warn('voice connection disconnected; reconnecting to channel', channel.guild.name, channel.name, e?.message || e);
|
|
1417
|
-
try {
|
|
1423
|
+
try { voiceConnection.destroy(); } catch {}
|
|
1418
1424
|
connection = null;
|
|
1419
1425
|
setTimeout(() => connectTo(channel).catch(err => warn('voice reconnect failed', err?.stack || err)), 1500);
|
|
1420
1426
|
}
|
|
1421
1427
|
}
|
|
1422
1428
|
});
|
|
1423
|
-
await entersState(
|
|
1424
|
-
|
|
1429
|
+
await entersState(voiceConnection, VoiceConnectionStatus.Ready, 30000);
|
|
1430
|
+
voiceConnection.receiver.speaking.on('start', userId => subscribeUser(voiceConnection.receiver, userId));
|
|
1425
1431
|
log(`Listening in voice channel ${channel.guild.name} / ${channel.name}`);
|
|
1426
1432
|
}
|
|
1427
1433
|
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Setup Wizard
|
|
4
4
|
|
|
5
|
+
Discord bot/application setup is intentionally not re-explained from scratch here. Use these upstream guides for the Discord-side steps, then return to VerbalCoding setup:
|
|
6
|
+
|
|
7
|
+
- Hermes Agent Discord messaging guide: <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/discord>
|
|
8
|
+
- Discord official bot overview: <https://docs.discord.com/developers/bots/overview>
|
|
9
|
+
- Discord official quick start: <https://docs.discord.com/developers/quick-start/getting-started>
|
|
10
|
+
|
|
5
11
|
```bash
|
|
6
12
|
./scripts/install.sh
|
|
7
13
|
```
|
package/docs/FRESH_INSTALL.md
CHANGED
|
@@ -77,6 +77,14 @@ If your OS is unsupported, install these manually before rerunning:
|
|
|
77
77
|
|
|
78
78
|
## 3. Discord application setup
|
|
79
79
|
|
|
80
|
+
Read the upstream Discord bot setup guides first if this is your first bot:
|
|
81
|
+
|
|
82
|
+
- Hermes Agent Discord messaging guide: <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/discord>
|
|
83
|
+
- Discord official bot overview: <https://docs.discord.com/developers/bots/overview>
|
|
84
|
+
- Discord official getting started guide: <https://docs.discord.com/developers/quick-start/getting-started>
|
|
85
|
+
|
|
86
|
+
Those pages show how to create a Discord application, add a bot user, enable privileged intents, and invite it to a server. VerbalCoding uses the same Discord bot setup, then adds voice receive, STT, CLI-agent execution, and TTS playback on top.
|
|
87
|
+
|
|
80
88
|
1. Create a Discord application and bot in the Discord Developer Portal.
|
|
81
89
|
2. Enable the Message Content privileged intent.
|
|
82
90
|
3. Copy the bot token into the installer prompt or `.env` as `DISCORD_BOT_TOKEN`.
|
package/docs/USAGE.md
CHANGED
|
@@ -43,6 +43,13 @@ The bot auto-joins the first configured channel name, defaulting to `일반,Gene
|
|
|
43
43
|
|
|
44
44
|
## Discord Commands
|
|
45
45
|
|
|
46
|
+
Before wiring commands, set up the Discord application/bot using the upstream guides:
|
|
47
|
+
|
|
48
|
+
- Hermes Agent Discord guide: <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/discord>
|
|
49
|
+
- Discord official bot docs: <https://docs.discord.com/developers/bots/overview>
|
|
50
|
+
|
|
51
|
+
Then use `vc bot invite CLIENT_ID` to generate the VerbalCoding-specific invite URL with text and voice permissions.
|
|
52
|
+
|
|
46
53
|
| Command | Purpose |
|
|
47
54
|
|---|---|
|
|
48
55
|
| `!ping` | Basic bot check |
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## 설정 마법사
|
|
4
4
|
|
|
5
|
+
Discord 봇/애플리케이션 생성 절차는 여기에서 처음부터 반복 설명하지 않습니다. Discord 쪽 설정은 아래 상위 문서를 보고 진행한 뒤 VerbalCoding 설정으로 돌아오세요.
|
|
6
|
+
|
|
7
|
+
- Hermes Agent Discord 메시징 가이드: <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/discord>
|
|
8
|
+
- Discord 공식 봇 개요: <https://docs.discord.com/developers/bots/overview>
|
|
9
|
+
- Discord 공식 시작 가이드: <https://docs.discord.com/developers/quick-start/getting-started>
|
|
10
|
+
|
|
5
11
|
npm으로 설치한 경우:
|
|
6
12
|
|
|
7
13
|
```bash
|
|
@@ -77,6 +77,14 @@ OS가 지원되지 않으면 아래를 직접 설치한 뒤 다시 실행하세
|
|
|
77
77
|
|
|
78
78
|
## 3. Discord 애플리케이션 설정
|
|
79
79
|
|
|
80
|
+
Discord 봇을 처음 만든다면 먼저 공식/상위 문서를 확인하세요.
|
|
81
|
+
|
|
82
|
+
- Hermes Agent Discord 메시징 가이드: <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/discord>
|
|
83
|
+
- Discord 공식 봇 개요: <https://docs.discord.com/developers/bots/overview>
|
|
84
|
+
- Discord 공식 시작 가이드: <https://docs.discord.com/developers/quick-start/getting-started>
|
|
85
|
+
|
|
86
|
+
위 문서에는 Discord 애플리케이션 생성, bot user 추가, privileged intent 활성화, 서버 초대 방법이 설명되어 있습니다. VerbalCoding도 같은 Discord bot 설정을 사용하고, 그 위에 음성 수신, STT, CLI 에이전트 실행, TTS 재생을 얹습니다.
|
|
87
|
+
|
|
80
88
|
1. Discord Developer Portal에서 애플리케이션과 봇을 만듭니다.
|
|
81
89
|
2. Message Content privileged intent를 켭니다.
|
|
82
90
|
3. 봇 토큰을 설치 프롬프트 또는 `.env`의 `DISCORD_BOT_TOKEN`에 넣습니다.
|
package/docs/i18n/USAGE.ko.md
CHANGED
|
@@ -51,6 +51,13 @@ VERBALCODING_INSTANCE_ENV=instances/my-project.env ./run.sh
|
|
|
51
51
|
|
|
52
52
|
## Discord 명령
|
|
53
53
|
|
|
54
|
+
명령을 연결하기 전에 먼저 상위 문서대로 Discord 애플리케이션/봇을 설정하세요.
|
|
55
|
+
|
|
56
|
+
- Hermes Agent Discord 가이드: <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/discord>
|
|
57
|
+
- Discord 공식 봇 문서: <https://docs.discord.com/developers/bots/overview>
|
|
58
|
+
|
|
59
|
+
그 다음 `vc bot invite CLIENT_ID`를 사용하면 VerbalCoding에 필요한 텍스트/음성 권한이 포함된 초대 URL을 만들 수 있습니다.
|
|
60
|
+
|
|
54
61
|
| 명령 | 용도 |
|
|
55
62
|
|---|---|
|
|
56
63
|
| `!ping` | 봇 연결 기본 확인 |
|