From 14b1d82e7287b4d3400dbc784ee3ee5e59e15869 Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 29 Jan 2026 15:41:04 -0800 Subject: [PATCH] Clarify WhatsApp self-chat mode in onboarding (#23) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improve Discord onboarding with detailed setup instructions - Add step-by-step instructions for creating Discord bot - Include guidance on enabling Message Content Intent - Show OAuth2 URL Generator steps with required permissions - Auto-generate invite URL after user enters bot token (extracts application ID from token and builds URL with correct permissions) 🐙 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta * Clarify WhatsApp and Signal self-chat mode in onboarding Changed confusing yes/no prompts to clearer selects: WhatsApp: - "Dedicated bot number" - Responds to all incoming messages - "My personal number" - Only responds to "Message Yourself" chat Signal (new): - "Dedicated bot number" - Responds to all incoming messages - "My personal number" - Only responds to "Note to Self" chat This makes it clear what each option actually does. Written by Cameron ◯ Letta Code "The question is not what you look at, but what you see." - Thoreau --------- Co-authored-by: Letta --- src/config/io.ts | 4 ++++ src/config/types.ts | 1 + src/onboard.ts | 32 ++++++++++++++++++++++++++------ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/config/io.ts b/src/config/io.ts index 355a10e..6c1719e 100644 --- a/src/config/io.ts +++ b/src/config/io.ts @@ -129,6 +129,10 @@ export function configToEnv(config: LettaBotConfig): Record { } if (config.channels.signal?.phone) { env.SIGNAL_PHONE_NUMBER = config.channels.signal.phone; + // Signal selfChat defaults to true, so only set env if explicitly false + if (config.channels.signal.selfChat === false) { + env.SIGNAL_SELF_CHAT_MODE = 'false'; + } } if (config.channels.discord?.token) { env.DISCORD_BOT_TOKEN = config.channels.discord.token; diff --git a/src/config/types.ts b/src/config/types.ts index e767671..de94df4 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -77,6 +77,7 @@ export interface WhatsAppConfig { export interface SignalConfig { enabled: boolean; phone?: string; + selfChat?: boolean; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[]; } diff --git a/src/onboard.ts b/src/onboard.ts index 057b04d..930eade 100644 --- a/src/onboard.ts +++ b/src/onboard.ts @@ -35,7 +35,7 @@ interface OnboardConfig { telegram: { enabled: boolean; token?: string; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] }; slack: { enabled: boolean; appToken?: string; botToken?: string; allowedUsers?: string[] }; whatsapp: { enabled: boolean; selfChat?: boolean; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] }; - signal: { enabled: boolean; phone?: string; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] }; + signal: { enabled: boolean; phone?: string; selfChat?: boolean; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] }; discord: { enabled: boolean; token?: string; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] }; gmail: { enabled: boolean; account?: string }; @@ -735,11 +735,15 @@ async function stepChannels(config: OnboardConfig, env: Record): 'WhatsApp' ); - const selfChat = await p.confirm({ - message: 'WhatsApp: Self-chat mode? (Message Yourself)', - initialValue: config.whatsapp.selfChat ?? false, + const selfChat = await p.select({ + message: 'WhatsApp: Whose number is this?', + options: [ + { value: 'dedicated', label: 'Dedicated bot number', hint: 'Responds to all incoming messages' }, + { value: 'personal', label: 'My personal number', hint: 'Only responds to "Message Yourself" chat' }, + ], + initialValue: config.whatsapp.selfChat ? 'personal' : 'dedicated', }); - if (!p.isCancel(selfChat)) config.whatsapp.selfChat = selfChat; + if (!p.isCancel(selfChat)) config.whatsapp.selfChat = selfChat === 'personal'; // Access control (important since WhatsApp has full account access) const dmPolicy = await p.select({ @@ -785,6 +789,16 @@ async function stepChannels(config: OnboardConfig, env: Record): }); if (!p.isCancel(phone) && phone) config.signal.phone = phone; + const selfChat = await p.select({ + message: 'Signal: Whose number is this?', + options: [ + { value: 'dedicated', label: 'Dedicated bot number', hint: 'Responds to all incoming messages' }, + { value: 'personal', label: 'My personal number', hint: 'Only responds to "Note to Self" chat' }, + ], + initialValue: config.signal.selfChat ? 'personal' : 'dedicated', + }); + if (!p.isCancel(selfChat)) config.signal.selfChat = selfChat === 'personal'; + // Access control const dmPolicy = await p.select({ message: 'Signal: Who can message the bot?', @@ -876,7 +890,7 @@ function showSummary(config: OnboardConfig): void { if (config.slack.enabled) channels.push('Slack'); if (config.discord.enabled) channels.push('Discord'); if (config.whatsapp.enabled) channels.push(config.whatsapp.selfChat ? 'WhatsApp (self)' : 'WhatsApp'); - if (config.signal.enabled) channels.push('Signal'); + if (config.signal.enabled) channels.push(config.signal.selfChat ? 'Signal (self)' : 'Signal'); lines.push(`Channels: ${channels.length > 0 ? channels.join(', ') : 'None'}`); // Features @@ -1000,6 +1014,7 @@ export async function onboard(): Promise { signal: { enabled: existingConfig.channels.signal?.enabled || false, phone: existingConfig.channels.signal?.phone, + selfChat: existingConfig.channels.signal?.selfChat, dmPolicy: existingConfig.channels.signal?.dmPolicy, }, gmail: { enabled: false }, @@ -1103,6 +1118,9 @@ export async function onboard(): Promise { if (config.signal.enabled && config.signal.phone) { env.SIGNAL_PHONE_NUMBER = config.signal.phone; + // Signal selfChat defaults to true, so only set env if explicitly false (dedicated number) + if (config.signal.selfChat === false) env.SIGNAL_SELF_CHAT_MODE = 'false'; + else delete env.SIGNAL_SELF_CHAT_MODE; if (config.signal.dmPolicy) env.SIGNAL_DM_POLICY = config.signal.dmPolicy; if (config.signal.allowedUsers?.length) { env.SIGNAL_ALLOWED_USERS = config.signal.allowedUsers.join(','); @@ -1111,6 +1129,7 @@ export async function onboard(): Promise { } } else { delete env.SIGNAL_PHONE_NUMBER; + delete env.SIGNAL_SELF_CHAT_MODE; delete env.SIGNAL_DM_POLICY; delete env.SIGNAL_ALLOWED_USERS; } @@ -1203,6 +1222,7 @@ export async function onboard(): Promise { signal: { enabled: true, phone: config.signal.phone, + selfChat: config.signal.selfChat, dmPolicy: config.signal.dmPolicy, allowedUsers: config.signal.allowedUsers, }