fix: CLI group settings handling and env var support (#257)
* Fix CLI group settings handling * Document group settings in config * fix: move group settings below channel list in README, add GROUP_DEBOUNCE_SEC env var - README: group settings section was splitting the cross-channel bullet list; moved it after the channel table - onboard.ts: groupDebounceSec had no env var override for non-interactive deploys; added <CHANNEL>_GROUP_DEBOUNCE_SEC for all 5 channels - SKILL.md: documented the new env var Written by Cameron and Letta Code "For every complex problem there is an answer that is clear, simple, and wrong." - H.L. Mencken --------- Co-authored-by: Jason Carreira <jason@visotrust.com> Co-authored-by: Cameron <cameron@pfiffer.org>
This commit is contained in:
14
README.md
14
README.md
@@ -211,6 +211,20 @@ Signal ────┘
|
||||
|
||||
At least one channel is required. Telegram is the easiest to start with.
|
||||
|
||||
### Group Settings (Optional)
|
||||
|
||||
Configure group batching and listening mode in `lettabot.yaml`:
|
||||
|
||||
```yaml
|
||||
channels:
|
||||
slack:
|
||||
groupDebounceSec: 5
|
||||
instantGroups: ["C0123456789"]
|
||||
listeningGroups: ["C0987654321"] # observe only, reply on mention
|
||||
```
|
||||
|
||||
See `SKILL.md` for the full environment variable list and examples.
|
||||
|
||||
## Bot Commands
|
||||
|
||||
| Command | Description |
|
||||
|
||||
48
SKILL.md
48
SKILL.md
@@ -176,6 +176,35 @@ Each channel supports three DM policies:
|
||||
- **`allowlist`**: Only specified user IDs can message
|
||||
- **`open`**: Anyone can message (not recommended)
|
||||
|
||||
## Group Settings (Optional)
|
||||
|
||||
Group settings apply to Telegram, Slack, Discord, WhatsApp, and Signal.
|
||||
|
||||
**YAML fields (per channel under `channels.<name>`):**
|
||||
- `groupDebounceSec`: Debounce seconds for group batching (default: 5)
|
||||
- `groupPollIntervalMin`: Deprecated (minutes)
|
||||
- `instantGroups`: Group IDs that bypass batching
|
||||
- `listeningGroups`: Group IDs where the bot observes and only replies when mentioned
|
||||
|
||||
**Environment variables (non-interactive onboarding):**
|
||||
- `<CHANNEL>_GROUP_DEBOUNCE_SEC` (seconds, e.g. `5`)
|
||||
- `<CHANNEL>_GROUP_POLL_INTERVAL_MIN` (deprecated, use `_GROUP_DEBOUNCE_SEC` instead)
|
||||
- `<CHANNEL>_INSTANT_GROUPS` (comma-separated)
|
||||
- `<CHANNEL>_LISTENING_GROUPS` (comma-separated)
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
channels:
|
||||
slack:
|
||||
enabled: true
|
||||
botToken: xoxb-...
|
||||
appToken: xapp-...
|
||||
groupDebounceSec: 5
|
||||
instantGroups: ["C0123456789"]
|
||||
listeningGroups: ["C0987654321"]
|
||||
```
|
||||
|
||||
## Configuration File
|
||||
|
||||
After onboarding, config is saved to `~/.lettabot/config.yaml`:
|
||||
@@ -186,16 +215,17 @@ server:
|
||||
apiKey: letta_...
|
||||
agentId: agent-...
|
||||
|
||||
telegram:
|
||||
enabled: true
|
||||
botToken: 123456:ABC-DEF...
|
||||
dmPolicy: pairing
|
||||
channels:
|
||||
telegram:
|
||||
enabled: true
|
||||
botToken: 123456:ABC-DEF...
|
||||
dmPolicy: pairing
|
||||
|
||||
slack:
|
||||
enabled: true
|
||||
botToken: xoxb-...
|
||||
appToken: xapp-...
|
||||
dmPolicy: pairing
|
||||
slack:
|
||||
enabled: true
|
||||
botToken: xoxb-...
|
||||
appToken: xapp-...
|
||||
dmPolicy: pairing
|
||||
```
|
||||
|
||||
Edit this file directly or re-run `lettabot onboard` to reconfigure.
|
||||
|
||||
@@ -41,6 +41,88 @@ export function getChannelHint(id: ChannelId): string {
|
||||
// Setup Functions
|
||||
// ============================================================================
|
||||
|
||||
function parseIdList(input?: string | null): string[] | undefined {
|
||||
if (!input) return undefined;
|
||||
const ids = input.split(',').map(s => s.trim()).filter(Boolean);
|
||||
return ids.length > 0 ? ids : undefined;
|
||||
}
|
||||
|
||||
async function promptGroupSettings(existing?: any): Promise<{
|
||||
groupDebounceSec?: number;
|
||||
groupPollIntervalMin?: number;
|
||||
instantGroups?: string[];
|
||||
listeningGroups?: string[];
|
||||
}> {
|
||||
const hasExisting = existing?.groupDebounceSec !== undefined
|
||||
|| existing?.groupPollIntervalMin !== undefined
|
||||
|| (existing?.instantGroups && existing.instantGroups.length > 0)
|
||||
|| (existing?.listeningGroups && existing.listeningGroups.length > 0);
|
||||
|
||||
const configure = await p.confirm({
|
||||
message: 'Configure group settings?',
|
||||
initialValue: hasExisting,
|
||||
});
|
||||
if (p.isCancel(configure)) {
|
||||
p.cancel('Cancelled');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!configure) {
|
||||
return {
|
||||
groupDebounceSec: existing?.groupDebounceSec,
|
||||
groupPollIntervalMin: existing?.groupPollIntervalMin,
|
||||
instantGroups: existing?.instantGroups,
|
||||
listeningGroups: existing?.listeningGroups,
|
||||
};
|
||||
}
|
||||
|
||||
const debounceRaw = await p.text({
|
||||
message: 'Group debounce seconds (blank = default)',
|
||||
placeholder: '5',
|
||||
initialValue: existing?.groupDebounceSec !== undefined ? String(existing.groupDebounceSec) : '',
|
||||
validate: (value) => {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return undefined;
|
||||
const num = Number(trimmed);
|
||||
if (!Number.isFinite(num) || num < 0) return 'Enter a non-negative number or leave blank';
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
if (p.isCancel(debounceRaw)) {
|
||||
p.cancel('Cancelled');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const instantRaw = await p.text({
|
||||
message: 'Instant group IDs (comma-separated, optional)',
|
||||
placeholder: '123,456',
|
||||
initialValue: Array.isArray(existing?.instantGroups) ? existing.instantGroups.join(',') : '',
|
||||
});
|
||||
if (p.isCancel(instantRaw)) {
|
||||
p.cancel('Cancelled');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const listeningRaw = await p.text({
|
||||
message: 'Listening group IDs (comma-separated, optional)',
|
||||
placeholder: '123,456',
|
||||
initialValue: Array.isArray(existing?.listeningGroups) ? existing.listeningGroups.join(',') : '',
|
||||
});
|
||||
if (p.isCancel(listeningRaw)) {
|
||||
p.cancel('Cancelled');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const debounceValue = debounceRaw?.trim() || '';
|
||||
|
||||
return {
|
||||
groupDebounceSec: debounceValue ? Number(debounceValue) : undefined,
|
||||
groupPollIntervalMin: existing?.groupPollIntervalMin,
|
||||
instantGroups: parseIdList(instantRaw),
|
||||
listeningGroups: parseIdList(listeningRaw),
|
||||
};
|
||||
}
|
||||
|
||||
export async function setupTelegram(existing?: any): Promise<any> {
|
||||
p.note(
|
||||
'1. Message @BotFather on Telegram\n' +
|
||||
@@ -90,11 +172,14 @@ export async function setupTelegram(existing?: any): Promise<any> {
|
||||
}
|
||||
}
|
||||
|
||||
const groupSettings = await promptGroupSettings(existing);
|
||||
|
||||
return {
|
||||
enabled: true,
|
||||
token: token || undefined,
|
||||
dmPolicy: dmPolicy as 'pairing' | 'allowlist' | 'open',
|
||||
allowedUsers,
|
||||
...groupSettings,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -131,11 +216,13 @@ export async function setupSlack(existing?: any): Promise<any> {
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const groupSettings = await promptGroupSettings(existing);
|
||||
return {
|
||||
enabled: true,
|
||||
appToken: result.appToken,
|
||||
botToken: result.botToken,
|
||||
allowedUsers: result.allowedUsers,
|
||||
...groupSettings,
|
||||
};
|
||||
}
|
||||
return { enabled: false }; // Wizard cancelled
|
||||
@@ -179,12 +266,14 @@ export async function setupSlack(existing?: any): Promise<any> {
|
||||
}
|
||||
|
||||
const allowedUsers = await stepAccessControl(existing?.allowedUsers);
|
||||
const groupSettings = await promptGroupSettings(existing);
|
||||
|
||||
return {
|
||||
enabled: true,
|
||||
appToken: appToken || undefined,
|
||||
botToken: botToken || undefined,
|
||||
allowedUsers,
|
||||
...groupSettings,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -256,11 +345,14 @@ export async function setupDiscord(existing?: any): Promise<any> {
|
||||
}
|
||||
}
|
||||
|
||||
const groupSettings = await promptGroupSettings(existing);
|
||||
|
||||
return {
|
||||
enabled: true,
|
||||
token: token || undefined,
|
||||
dmPolicy: dmPolicy as 'pairing' | 'allowlist' | 'open',
|
||||
allowedUsers,
|
||||
...groupSettings,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -313,6 +405,8 @@ export async function setupWhatsApp(existing?: any): Promise<any> {
|
||||
}
|
||||
}
|
||||
|
||||
const groupSettings = await promptGroupSettings(existing);
|
||||
|
||||
p.log.info('Run "lettabot server" to see the QR code and complete pairing.');
|
||||
|
||||
return {
|
||||
@@ -320,6 +414,7 @@ export async function setupWhatsApp(existing?: any): Promise<any> {
|
||||
selfChat: isSelfChat,
|
||||
dmPolicy,
|
||||
allowedUsers,
|
||||
...groupSettings,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -399,12 +494,15 @@ export async function setupSignal(existing?: any): Promise<any> {
|
||||
}
|
||||
}
|
||||
|
||||
const groupSettings = await promptGroupSettings(existing);
|
||||
|
||||
return {
|
||||
enabled: true,
|
||||
phone: phone || undefined,
|
||||
selfChat: isSelfChat,
|
||||
dmPolicy,
|
||||
allowedUsers,
|
||||
...groupSettings,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
148
src/onboard.ts
148
src/onboard.ts
@@ -15,6 +15,18 @@ import { CHANNELS, getChannelHint, isSignalCliInstalled, setupTelegram, setupSla
|
||||
// Non-Interactive Helpers
|
||||
// ============================================================================
|
||||
|
||||
function parseCsvList(value?: string): string[] | undefined {
|
||||
if (!value) return undefined;
|
||||
const items = value.split(',').map(s => s.trim()).filter(Boolean);
|
||||
return items.length > 0 ? items : undefined;
|
||||
}
|
||||
|
||||
function parseOptionalInt(value?: string): number | undefined {
|
||||
if (!value) return undefined;
|
||||
const parsed = parseInt(value, 10);
|
||||
return Number.isFinite(parsed) ? parsed : undefined;
|
||||
}
|
||||
|
||||
function readConfigFromEnv(existingConfig: any): any {
|
||||
return {
|
||||
baseUrl: process.env.LETTA_BASE_URL || existingConfig.server?.baseUrl || 'https://api.letta.com',
|
||||
@@ -27,6 +39,14 @@ function readConfigFromEnv(existingConfig: any): any {
|
||||
botToken: process.env.TELEGRAM_BOT_TOKEN || existingConfig.channels?.telegram?.token,
|
||||
dmPolicy: process.env.TELEGRAM_DM_POLICY || existingConfig.channels?.telegram?.dmPolicy || 'pairing',
|
||||
allowedUsers: process.env.TELEGRAM_ALLOWED_USERS?.split(',').map(s => s.trim()) || existingConfig.channels?.telegram?.allowedUsers,
|
||||
groupDebounceSec: parseOptionalInt(process.env.TELEGRAM_GROUP_DEBOUNCE_SEC)
|
||||
?? existingConfig.channels?.telegram?.groupDebounceSec,
|
||||
groupPollIntervalMin: parseOptionalInt(process.env.TELEGRAM_GROUP_POLL_INTERVAL_MIN)
|
||||
?? existingConfig.channels?.telegram?.groupPollIntervalMin,
|
||||
instantGroups: parseCsvList(process.env.TELEGRAM_INSTANT_GROUPS)
|
||||
?? existingConfig.channels?.telegram?.instantGroups,
|
||||
listeningGroups: parseCsvList(process.env.TELEGRAM_LISTENING_GROUPS)
|
||||
?? existingConfig.channels?.telegram?.listeningGroups,
|
||||
},
|
||||
|
||||
slack: {
|
||||
@@ -35,6 +55,14 @@ function readConfigFromEnv(existingConfig: any): any {
|
||||
appToken: process.env.SLACK_APP_TOKEN || existingConfig.channels?.slack?.appToken,
|
||||
dmPolicy: process.env.SLACK_DM_POLICY || existingConfig.channels?.slack?.dmPolicy || 'pairing',
|
||||
allowedUsers: process.env.SLACK_ALLOWED_USERS?.split(',').map(s => s.trim()) || existingConfig.channels?.slack?.allowedUsers,
|
||||
groupDebounceSec: parseOptionalInt(process.env.SLACK_GROUP_DEBOUNCE_SEC)
|
||||
?? existingConfig.channels?.slack?.groupDebounceSec,
|
||||
groupPollIntervalMin: parseOptionalInt(process.env.SLACK_GROUP_POLL_INTERVAL_MIN)
|
||||
?? existingConfig.channels?.slack?.groupPollIntervalMin,
|
||||
instantGroups: parseCsvList(process.env.SLACK_INSTANT_GROUPS)
|
||||
?? existingConfig.channels?.slack?.instantGroups,
|
||||
listeningGroups: parseCsvList(process.env.SLACK_LISTENING_GROUPS)
|
||||
?? existingConfig.channels?.slack?.listeningGroups,
|
||||
},
|
||||
|
||||
discord: {
|
||||
@@ -42,6 +70,14 @@ function readConfigFromEnv(existingConfig: any): any {
|
||||
botToken: process.env.DISCORD_BOT_TOKEN || existingConfig.channels?.discord?.token,
|
||||
dmPolicy: process.env.DISCORD_DM_POLICY || existingConfig.channels?.discord?.dmPolicy || 'pairing',
|
||||
allowedUsers: process.env.DISCORD_ALLOWED_USERS?.split(',').map(s => s.trim()) || existingConfig.channels?.discord?.allowedUsers,
|
||||
groupDebounceSec: parseOptionalInt(process.env.DISCORD_GROUP_DEBOUNCE_SEC)
|
||||
?? existingConfig.channels?.discord?.groupDebounceSec,
|
||||
groupPollIntervalMin: parseOptionalInt(process.env.DISCORD_GROUP_POLL_INTERVAL_MIN)
|
||||
?? existingConfig.channels?.discord?.groupPollIntervalMin,
|
||||
instantGroups: parseCsvList(process.env.DISCORD_INSTANT_GROUPS)
|
||||
?? existingConfig.channels?.discord?.instantGroups,
|
||||
listeningGroups: parseCsvList(process.env.DISCORD_LISTENING_GROUPS)
|
||||
?? existingConfig.channels?.discord?.listeningGroups,
|
||||
},
|
||||
|
||||
whatsapp: {
|
||||
@@ -49,6 +85,14 @@ function readConfigFromEnv(existingConfig: any): any {
|
||||
selfChat: process.env.WHATSAPP_SELF_CHAT_MODE !== 'false' && (existingConfig.channels?.whatsapp?.selfChat !== false),
|
||||
dmPolicy: process.env.WHATSAPP_DM_POLICY || existingConfig.channels?.whatsapp?.dmPolicy || 'pairing',
|
||||
allowedUsers: process.env.WHATSAPP_ALLOWED_USERS?.split(',').map(s => s.trim()) || existingConfig.channels?.whatsapp?.allowedUsers,
|
||||
groupDebounceSec: parseOptionalInt(process.env.WHATSAPP_GROUP_DEBOUNCE_SEC)
|
||||
?? existingConfig.channels?.whatsapp?.groupDebounceSec,
|
||||
groupPollIntervalMin: parseOptionalInt(process.env.WHATSAPP_GROUP_POLL_INTERVAL_MIN)
|
||||
?? existingConfig.channels?.whatsapp?.groupPollIntervalMin,
|
||||
instantGroups: parseCsvList(process.env.WHATSAPP_INSTANT_GROUPS)
|
||||
?? existingConfig.channels?.whatsapp?.instantGroups,
|
||||
listeningGroups: parseCsvList(process.env.WHATSAPP_LISTENING_GROUPS)
|
||||
?? existingConfig.channels?.whatsapp?.listeningGroups,
|
||||
},
|
||||
|
||||
signal: {
|
||||
@@ -57,6 +101,14 @@ function readConfigFromEnv(existingConfig: any): any {
|
||||
selfChat: process.env.SIGNAL_SELF_CHAT_MODE !== 'false' && (existingConfig.channels?.signal?.selfChat !== false),
|
||||
dmPolicy: process.env.SIGNAL_DM_POLICY || existingConfig.channels?.signal?.dmPolicy || 'pairing',
|
||||
allowedUsers: process.env.SIGNAL_ALLOWED_USERS?.split(',').map(s => s.trim()) || existingConfig.channels?.signal?.allowedUsers,
|
||||
groupDebounceSec: parseOptionalInt(process.env.SIGNAL_GROUP_DEBOUNCE_SEC)
|
||||
?? existingConfig.channels?.signal?.groupDebounceSec,
|
||||
groupPollIntervalMin: parseOptionalInt(process.env.SIGNAL_GROUP_POLL_INTERVAL_MIN)
|
||||
?? existingConfig.channels?.signal?.groupPollIntervalMin,
|
||||
instantGroups: parseCsvList(process.env.SIGNAL_INSTANT_GROUPS)
|
||||
?? existingConfig.channels?.signal?.instantGroups,
|
||||
listeningGroups: parseCsvList(process.env.SIGNAL_LISTENING_GROUPS)
|
||||
?? existingConfig.channels?.signal?.listeningGroups,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -81,6 +133,10 @@ async function saveConfigFromEnv(config: any, configPath: string): Promise<void>
|
||||
token: config.telegram.botToken,
|
||||
dmPolicy: config.telegram.dmPolicy,
|
||||
allowedUsers: config.telegram.allowedUsers,
|
||||
groupDebounceSec: config.telegram.groupDebounceSec,
|
||||
groupPollIntervalMin: config.telegram.groupPollIntervalMin,
|
||||
instantGroups: config.telegram.instantGroups,
|
||||
listeningGroups: config.telegram.listeningGroups,
|
||||
} : { enabled: false },
|
||||
|
||||
slack: config.slack.enabled ? {
|
||||
@@ -88,6 +144,10 @@ async function saveConfigFromEnv(config: any, configPath: string): Promise<void>
|
||||
botToken: config.slack.botToken,
|
||||
appToken: config.slack.appToken,
|
||||
allowedUsers: config.slack.allowedUsers,
|
||||
groupDebounceSec: config.slack.groupDebounceSec,
|
||||
groupPollIntervalMin: config.slack.groupPollIntervalMin,
|
||||
instantGroups: config.slack.instantGroups,
|
||||
listeningGroups: config.slack.listeningGroups,
|
||||
} : { enabled: false },
|
||||
|
||||
discord: config.discord.enabled ? {
|
||||
@@ -95,6 +155,10 @@ async function saveConfigFromEnv(config: any, configPath: string): Promise<void>
|
||||
token: config.discord.botToken,
|
||||
dmPolicy: config.discord.dmPolicy,
|
||||
allowedUsers: config.discord.allowedUsers,
|
||||
groupDebounceSec: config.discord.groupDebounceSec,
|
||||
groupPollIntervalMin: config.discord.groupPollIntervalMin,
|
||||
instantGroups: config.discord.instantGroups,
|
||||
listeningGroups: config.discord.listeningGroups,
|
||||
} : { enabled: false },
|
||||
|
||||
whatsapp: config.whatsapp.enabled ? {
|
||||
@@ -102,6 +166,10 @@ async function saveConfigFromEnv(config: any, configPath: string): Promise<void>
|
||||
selfChat: config.whatsapp.selfChat,
|
||||
dmPolicy: config.whatsapp.dmPolicy,
|
||||
allowedUsers: config.whatsapp.allowedUsers,
|
||||
groupDebounceSec: config.whatsapp.groupDebounceSec,
|
||||
groupPollIntervalMin: config.whatsapp.groupPollIntervalMin,
|
||||
instantGroups: config.whatsapp.instantGroups,
|
||||
listeningGroups: config.whatsapp.listeningGroups,
|
||||
} : { enabled: false },
|
||||
|
||||
signal: config.signal.enabled ? {
|
||||
@@ -110,6 +178,10 @@ async function saveConfigFromEnv(config: any, configPath: string): Promise<void>
|
||||
selfChat: config.signal.selfChat,
|
||||
dmPolicy: config.signal.dmPolicy,
|
||||
allowedUsers: config.signal.allowedUsers,
|
||||
groupDebounceSec: config.signal.groupDebounceSec,
|
||||
groupPollIntervalMin: config.signal.groupPollIntervalMin,
|
||||
instantGroups: config.signal.instantGroups,
|
||||
listeningGroups: config.signal.listeningGroups,
|
||||
} : { enabled: false },
|
||||
},
|
||||
features: {
|
||||
@@ -147,11 +219,57 @@ interface OnboardConfig {
|
||||
providers?: Array<{ id: string; name: string; apiKey: string }>;
|
||||
|
||||
// Channels (with access control)
|
||||
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; selfChat?: boolean; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] };
|
||||
discord: { enabled: boolean; token?: string; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] };
|
||||
telegram: {
|
||||
enabled: boolean;
|
||||
token?: string;
|
||||
dmPolicy?: 'pairing' | 'allowlist' | 'open';
|
||||
allowedUsers?: string[];
|
||||
groupDebounceSec?: number;
|
||||
groupPollIntervalMin?: number;
|
||||
instantGroups?: string[];
|
||||
listeningGroups?: string[];
|
||||
};
|
||||
slack: {
|
||||
enabled: boolean;
|
||||
appToken?: string;
|
||||
botToken?: string;
|
||||
allowedUsers?: string[];
|
||||
groupDebounceSec?: number;
|
||||
groupPollIntervalMin?: number;
|
||||
instantGroups?: string[];
|
||||
listeningGroups?: string[];
|
||||
};
|
||||
whatsapp: {
|
||||
enabled: boolean;
|
||||
selfChat?: boolean;
|
||||
dmPolicy?: 'pairing' | 'allowlist' | 'open';
|
||||
allowedUsers?: string[];
|
||||
groupDebounceSec?: number;
|
||||
groupPollIntervalMin?: number;
|
||||
instantGroups?: string[];
|
||||
listeningGroups?: string[];
|
||||
};
|
||||
signal: {
|
||||
enabled: boolean;
|
||||
phone?: string;
|
||||
selfChat?: boolean;
|
||||
dmPolicy?: 'pairing' | 'allowlist' | 'open';
|
||||
allowedUsers?: string[];
|
||||
groupDebounceSec?: number;
|
||||
groupPollIntervalMin?: number;
|
||||
instantGroups?: string[];
|
||||
listeningGroups?: string[];
|
||||
};
|
||||
discord: {
|
||||
enabled: boolean;
|
||||
token?: string;
|
||||
dmPolicy?: 'pairing' | 'allowlist' | 'open';
|
||||
allowedUsers?: string[];
|
||||
groupDebounceSec?: number;
|
||||
groupPollIntervalMin?: number;
|
||||
instantGroups?: string[];
|
||||
listeningGroups?: string[];
|
||||
};
|
||||
|
||||
// Google Workspace (via gog CLI)
|
||||
google: { enabled: boolean; accounts: Array<{ account: string; services: string[] }> };
|
||||
@@ -1525,6 +1643,10 @@ export async function onboard(options?: { nonInteractive?: boolean }): Promise<v
|
||||
token: config.telegram.token,
|
||||
dmPolicy: config.telegram.dmPolicy,
|
||||
allowedUsers: config.telegram.allowedUsers,
|
||||
groupDebounceSec: config.telegram.groupDebounceSec,
|
||||
groupPollIntervalMin: config.telegram.groupPollIntervalMin,
|
||||
instantGroups: config.telegram.instantGroups,
|
||||
listeningGroups: config.telegram.listeningGroups,
|
||||
}
|
||||
} : {}),
|
||||
...(config.slack.enabled ? {
|
||||
@@ -1533,6 +1655,10 @@ export async function onboard(options?: { nonInteractive?: boolean }): Promise<v
|
||||
appToken: config.slack.appToken,
|
||||
botToken: config.slack.botToken,
|
||||
allowedUsers: config.slack.allowedUsers,
|
||||
groupDebounceSec: config.slack.groupDebounceSec,
|
||||
groupPollIntervalMin: config.slack.groupPollIntervalMin,
|
||||
instantGroups: config.slack.instantGroups,
|
||||
listeningGroups: config.slack.listeningGroups,
|
||||
}
|
||||
} : {}),
|
||||
...(config.discord.enabled ? {
|
||||
@@ -1541,6 +1667,10 @@ export async function onboard(options?: { nonInteractive?: boolean }): Promise<v
|
||||
token: config.discord.token,
|
||||
dmPolicy: config.discord.dmPolicy,
|
||||
allowedUsers: config.discord.allowedUsers,
|
||||
groupDebounceSec: config.discord.groupDebounceSec,
|
||||
groupPollIntervalMin: config.discord.groupPollIntervalMin,
|
||||
instantGroups: config.discord.instantGroups,
|
||||
listeningGroups: config.discord.listeningGroups,
|
||||
}
|
||||
} : {}),
|
||||
...(config.whatsapp.enabled ? {
|
||||
@@ -1549,6 +1679,10 @@ export async function onboard(options?: { nonInteractive?: boolean }): Promise<v
|
||||
selfChat: config.whatsapp.selfChat,
|
||||
dmPolicy: config.whatsapp.dmPolicy,
|
||||
allowedUsers: config.whatsapp.allowedUsers,
|
||||
groupDebounceSec: config.whatsapp.groupDebounceSec,
|
||||
groupPollIntervalMin: config.whatsapp.groupPollIntervalMin,
|
||||
instantGroups: config.whatsapp.instantGroups,
|
||||
listeningGroups: config.whatsapp.listeningGroups,
|
||||
}
|
||||
} : {}),
|
||||
...(config.signal.enabled ? {
|
||||
@@ -1558,6 +1692,10 @@ export async function onboard(options?: { nonInteractive?: boolean }): Promise<v
|
||||
selfChat: config.signal.selfChat,
|
||||
dmPolicy: config.signal.dmPolicy,
|
||||
allowedUsers: config.signal.allowedUsers,
|
||||
groupDebounceSec: config.signal.groupDebounceSec,
|
||||
groupPollIntervalMin: config.signal.groupPollIntervalMin,
|
||||
instantGroups: config.signal.instantGroups,
|
||||
listeningGroups: config.signal.listeningGroups,
|
||||
}
|
||||
} : {}),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user