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.
@@ -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 || '123456789012345678').trim(),
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.subscribe(player);
1406
- connection.on('error', e => warn('voice connection error', e?.stack || e));
1407
- connection.on('stateChange', async (oldState, newState) => {
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(connection, VoiceConnectionStatus.Signalling, 5000),
1413
- entersState(connection, VoiceConnectionStatus.Connecting, 5000),
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 { connection?.destroy(); } catch {}
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(connection, VoiceConnectionStatus.Ready, 30000);
1424
- connection.receiver.speaking.on('start', userId => subscribeUser(connection.receiver, userId));
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
 
@@ -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
  ```
@@ -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`에 넣습니다.
@@ -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` | 봇 연결 기본 확인 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "verbalcoding",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Discord voice bridge for CLI coding agents.",
5
5
  "license": "MIT",
6
6
  "repository": {