feat(discord): make the typed first-message hint a separate opt-in, off by default

Claude keeps the silent system-prompt hint (startupHint, on). Other CLIs are sent the typed message only with typedHint, which costs a model turn per tab.
This commit is contained in:
Devvyn committed 2026-10-30 01:38:37 +08:00
1 parent e95d38a944
commit 6d4357502b
10 files changed
+77 -27

No files matched your search

+20 -2
View File
@@ -3,7 +3,16 @@
* @fileoverview Discord bridge: pure rules, the 0600 store, the REST client, the gateway state
* machine (fake socket) and the bridge's gates. No network, no real Discord.
*/
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, symlinkSync, writeFileSync } from 'node:fs';
import {
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
statSync,
symlinkSync,
writeFileSync,
} from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
@@ -634,7 +643,7 @@ describe('DiscordBridge files and startup hint', () => {
now: () => t,
sleep: async () => undefined,
});
return writeDiscordConfig(dir, { ...CFG, ...cfg }).then(async () => {
return writeDiscordConfig(dir, { ...CFG, typedHint: true, ...cfg }).then(async () => {
await b.reload();
await b.notify(MSG);
posted.length = 0;
@@ -730,6 +739,15 @@ describe('DiscordBridge files and startup hint', () => {
b.stop();
});
it('sends the typed hint only when typedHint is on (the default is off)', async () => {
const off = await make({ typedHint: false });
await off.sessionCreated('s7', 'new', t - 1000);
await off.sessionIdle('s7', true);
expect(sent).toHaveLength(0);
off.stop();
expect(DEFAULT_DISCORD_CONFIG.typedHint).toBe(false);
});
it('does not hint a restored (old) session, or when startupHint is off', async () => {
const b = await make();
await b.sessionCreated('s4', 'old', 1); // created long ago: restored at server start
+13
View File
@@ -79,6 +79,19 @@ describe('/api/discord', () => {
bridge.stop();
});
it('stores startupHint (default on) and typedHint (default off) and returns them', async () => {
const { app, bridge } = await harness();
const first = (await app.inject({ method: 'GET', url: '/api/discord' })).json().data;
expect(first).toMatchObject({ startupHint: true, typedHint: false });
const put = await app.inject({
method: 'PUT',
url: '/api/discord',
payload: { typedHint: true, startupHint: false },
});
expect(put.json().data).toMatchObject({ startupHint: false, typedHint: true });
bridge.stop();
});
it('refuses a bad id, an incomplete enable, and unknown fields', async () => {
const { app } = await harness();
const bad = await app.inject({ method: 'PUT', url: '/api/discord', payload: { guildId: 'not-a-number' } });