feat: add non-interactive onboarding and SKILL.md (#45)
* feat: add non-interactive onboarding and SKILL.md Add agent-friendly setup flow: - lettabot onboard --non-interactive flag - Reads all config from environment variables - SKILL.md documents env-based setup for agents - Supports all channels (Telegram, Slack, Discord, WhatsApp, Signal) - No prompts - ideal for coding agents automating setup 👾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta <noreply@letta.com> * fix: address non-interactive setup issues - Add SLACK_APP_NAME for customizable app name (defaults to LETTA_AGENT_NAME or LettaBot) - Clarify WhatsApp requires WHATSAPP_ENABLED and WHATSAPP_SELF_CHAT to be explicit - Document all 5 channels supported (Telegram, Slack, Discord, WhatsApp, Signal) - Fix WhatsApp selfChat default to be explicit false * docs: recommend non-interactive setup as primary method Update README per review feedback to show env-based setup first. This is simpler for most users and ideal for automation. * docs: rewrite setup to be AI-first per feedback Make recommended setup AI-focused: - Show prompt to paste into AI coding assistants - AI handles clone/install/config autonomously - Manual wizard becomes Option 2 for human users --------- Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
24
README.md
24
README.md
@@ -50,9 +50,29 @@ See the [documentation](https://docs.letta.com/guides/docker/) for more details
|
||||
|
||||
### Setup
|
||||
|
||||
Run the interactive onboarding wizard:
|
||||
**Option 1: AI-Assisted Setup (Recommended)**
|
||||
|
||||
Paste this into Letta Code, Claude Code, Codex CLI, or any AI coding assistant:
|
||||
|
||||
```
|
||||
Clone https://github.com/letta-ai/lettabot, read the SKILL.md
|
||||
for setup instructions, and help me configure Telegram.
|
||||
```
|
||||
|
||||
You'll need:
|
||||
- A Letta API key from [app.letta.com](https://app.letta.com) (or a [Letta Docker server](https://docs.letta.com/guides/docker/))
|
||||
- A Telegram bot token from [@BotFather](https://t.me/BotFather)
|
||||
|
||||
The AI will handle the rest: cloning, installing dependencies, reading setup docs, and configuring your bot.
|
||||
|
||||
**Option 2: Interactive Wizard**
|
||||
|
||||
For manual step-by-step setup:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/letta-ai/lettabot.git
|
||||
cd lettabot
|
||||
npm install && npm run build && npm link
|
||||
lettabot onboard
|
||||
```
|
||||
|
||||
@@ -64,6 +84,8 @@ lettabot server
|
||||
|
||||
That's it! Message your bot on Telegram.
|
||||
|
||||
> **Note:** For detailed environment variable reference and multi-channel setup, see [SKILL.md](./SKILL.md)
|
||||
|
||||
## Skills
|
||||
LettaBot is compatible with [skills.sh](https://skills.sh) and [Clawdhub](https://clawdhub.com/).
|
||||
|
||||
|
||||
295
SKILL.md
Normal file
295
SKILL.md
Normal file
@@ -0,0 +1,295 @@
|
||||
---
|
||||
name: lettabot
|
||||
description: Set up and run LettaBot - a multi-channel AI assistant for Telegram, Slack, Discord, WhatsApp, and Signal. Supports both interactive wizard and non-interactive (agent-friendly) configuration.
|
||||
---
|
||||
|
||||
# LettaBot Setup
|
||||
|
||||
Multi-channel AI assistant with persistent memory across Telegram, Slack, Discord, WhatsApp, and Signal.
|
||||
|
||||
## Quick Setup (Agent-Friendly)
|
||||
|
||||
For non-interactive setup (ideal for coding agents):
|
||||
|
||||
```bash
|
||||
# 1. Clone and install
|
||||
git clone https://github.com/letta-ai/lettabot.git
|
||||
cd lettabot
|
||||
npm install
|
||||
npm run build
|
||||
npm link
|
||||
|
||||
# 2. Configure via environment variables
|
||||
export LETTA_API_KEY="letta_..." # From app.letta.com
|
||||
export LETTA_BASE_URL="https://api.letta.com" # Or self-hosted
|
||||
export LETTA_AGENT_ID="agent-..." # Optional: use existing agent
|
||||
|
||||
# 3. Configure channel (example: Telegram)
|
||||
export TELEGRAM_BOT_TOKEN="123456:ABC-DEF..." # From @BotFather
|
||||
export TELEGRAM_DM_POLICY="pairing" # Optional: pairing | allowlist | open
|
||||
|
||||
# 4. Run non-interactive setup
|
||||
lettabot onboard --non-interactive
|
||||
|
||||
# 5. Start the bot
|
||||
lettabot server
|
||||
```
|
||||
|
||||
## Interactive Setup
|
||||
|
||||
For human-friendly setup with wizard:
|
||||
|
||||
```bash
|
||||
lettabot onboard
|
||||
```
|
||||
|
||||
The wizard will guide you through:
|
||||
- Letta API authentication (OAuth or API key)
|
||||
- Agent selection/creation
|
||||
- Channel configuration (Telegram, Slack, Discord, WhatsApp, Signal)
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Required
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `LETTA_API_KEY` | API key from app.letta.com (or skip for OAuth) |
|
||||
| `LETTA_BASE_URL` | API endpoint (default: https://api.letta.com) |
|
||||
|
||||
### Agent Selection
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `LETTA_AGENT_ID` | Use existing agent (skip agent creation) |
|
||||
| `LETTA_AGENT_NAME` | Name for new agent (default: "lettabot") |
|
||||
| `LETTA_MODEL` | Model for new agent (default: "claude-sonnet-4") |
|
||||
|
||||
### Telegram
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `TELEGRAM_BOT_TOKEN` | Bot token from @BotFather | ✅ |
|
||||
| `TELEGRAM_DM_POLICY` | Access control: `pairing` \| `allowlist` \| `open` | ❌ (default: pairing) |
|
||||
| `TELEGRAM_ALLOWED_USERS` | Comma-separated user IDs (if dmPolicy=allowlist) | ❌ |
|
||||
|
||||
### Slack (Socket Mode)
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `SLACK_BOT_TOKEN` | Bot User OAuth Token (xoxb-...) | ✅ |
|
||||
| `SLACK_APP_TOKEN` | App-Level Token (xapp-...) for Socket Mode | ✅ |
|
||||
| `SLACK_APP_NAME` | Custom app name (default: LETTA_AGENT_NAME or "LettaBot") | ❌ |
|
||||
| `SLACK_DM_POLICY` | Access control: `pairing` \| `allowlist` \| `open` | ❌ (default: pairing) |
|
||||
| `SLACK_ALLOWED_USERS` | Comma-separated Slack user IDs (if dmPolicy=allowlist) | ❌ |
|
||||
|
||||
**Setup Slack app:** See [Slack Setup Wizard](./src/setup/slack-wizard.ts) or run `lettabot onboard` for guided setup.
|
||||
|
||||
### Discord
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `DISCORD_BOT_TOKEN` | Bot token from discord.com/developers/applications | ✅ |
|
||||
| `DISCORD_DM_POLICY` | Access control: `pairing` \| `allowlist` \| `open` | ❌ (default: pairing) |
|
||||
| `DISCORD_ALLOWED_USERS` | Comma-separated Discord user IDs (if dmPolicy=allowlist) | ❌ |
|
||||
|
||||
**Setup Discord bot:** See [docs/discord-setup.md](./docs/discord-setup.md)
|
||||
|
||||
### WhatsApp
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `WHATSAPP_ENABLED` | Enable WhatsApp: `true` \| `false` | ✅ Must be explicit |
|
||||
| `WHATSAPP_SELF_CHAT` | Self-chat mode: `true` (personal number) \| `false` (dedicated bot number) | ✅ Must be explicit |
|
||||
| `WHATSAPP_DM_POLICY` | Access control: `pairing` \| `allowlist` \| `open` | ❌ (default: pairing) |
|
||||
| `WHATSAPP_ALLOWED_USERS` | Comma-separated phone numbers with + (if dmPolicy=allowlist) | ❌ |
|
||||
|
||||
**Important:**
|
||||
- `WHATSAPP_SELF_CHAT=false` (dedicated bot number): Responds to ALL incoming messages
|
||||
- `WHATSAPP_SELF_CHAT=true` (personal number): Only responds to "Message Yourself" chat
|
||||
- QR code appears on first run - scan with WhatsApp app
|
||||
|
||||
### Signal
|
||||
|
||||
| Variable | Description | Required |
|
||||
|----------|-------------|----------|
|
||||
| `SIGNAL_PHONE_NUMBER` | Your phone number (with +) | ✅ |
|
||||
| `SIGNAL_DM_POLICY` | Access control: `pairing` \| `allowlist` \| `open` | ❌ (default: pairing) |
|
||||
| `SIGNAL_ALLOWED_USERS` | Comma-separated phone numbers with + (if dmPolicy=allowlist) | ❌ |
|
||||
|
||||
**Setup:** Requires Signal CLI - see [signal-cli documentation](https://github.com/AsamK/signal-cli).
|
||||
|
||||
## Channel-Specific Setup
|
||||
|
||||
### Telegram Bot Setup
|
||||
|
||||
1. Message [@BotFather](https://t.me/BotFather) on Telegram
|
||||
2. Send `/newbot` and follow prompts
|
||||
3. Copy the token (format: `123456:ABC-DEF...`)
|
||||
4. Set `TELEGRAM_BOT_TOKEN` environment variable
|
||||
|
||||
### Slack App Setup (Interactive)
|
||||
|
||||
For Socket Mode (required for real-time messages):
|
||||
|
||||
```bash
|
||||
lettabot onboard
|
||||
# Select "Slack" → "Guided setup"
|
||||
```
|
||||
|
||||
This uses a manifest to pre-configure:
|
||||
- Socket Mode
|
||||
- 5 bot scopes (app_mentions:read, chat:write, im:*)
|
||||
- 2 event subscriptions (app_mention, message.im)
|
||||
|
||||
### Slack App Setup (Manual)
|
||||
|
||||
1. Go to [api.slack.com/apps](https://api.slack.com/apps)
|
||||
2. Create app from manifest (see `src/setup/slack-wizard.ts` for manifest YAML)
|
||||
3. Install to workspace → copy Bot Token (`xoxb-...`)
|
||||
4. Enable Socket Mode → generate App Token (`xapp-...`)
|
||||
5. Set both tokens in environment
|
||||
|
||||
## Access Control
|
||||
|
||||
Each channel supports three DM policies:
|
||||
|
||||
- **`pairing`** (recommended): Users get a code, you approve via `lettabot pairing approve <channel> <code>`
|
||||
- **`allowlist`**: Only specified user IDs can message
|
||||
- **`open`**: Anyone can message (not recommended)
|
||||
|
||||
## Configuration File
|
||||
|
||||
After onboarding, config is saved to `~/.config/lettabot/config.yaml`:
|
||||
|
||||
```yaml
|
||||
server:
|
||||
baseUrl: https://api.letta.com
|
||||
apiKey: letta_...
|
||||
agentId: agent-...
|
||||
|
||||
telegram:
|
||||
enabled: true
|
||||
botToken: 123456:ABC-DEF...
|
||||
dmPolicy: pairing
|
||||
|
||||
slack:
|
||||
enabled: true
|
||||
botToken: xoxb-...
|
||||
appToken: xapp-...
|
||||
dmPolicy: pairing
|
||||
```
|
||||
|
||||
Edit this file directly or re-run `lettabot onboard` to reconfigure.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Setup
|
||||
lettabot onboard # Interactive wizard
|
||||
lettabot onboard --non-interactive # Env-based setup (agent-friendly)
|
||||
|
||||
# Run
|
||||
lettabot server # Start bot server
|
||||
|
||||
# Manage
|
||||
lettabot pairing list # List pending pairing requests
|
||||
lettabot pairing approve <channel> <code> # Approve user
|
||||
lettabot skills # Enable/disable skills
|
||||
|
||||
# Scheduling
|
||||
lettabot cron list # List scheduled tasks
|
||||
lettabot cron add "Daily standup at 9am" "0 9 * * *" # Add cron job
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Module not found" errors
|
||||
|
||||
Make sure you've run `npm run build` after installing or pulling updates.
|
||||
|
||||
### Telegram bot not responding
|
||||
|
||||
1. Check token is correct: `curl https://api.telegram.org/bot<TOKEN>/getMe`
|
||||
2. Ensure bot is started: `lettabot server` should show "Connected to Telegram"
|
||||
3. Check access control: User may need pairing approval
|
||||
|
||||
### Slack not receiving messages
|
||||
|
||||
1. Verify Socket Mode is enabled in Slack app settings
|
||||
2. Check both tokens are set: `SLACK_BOT_TOKEN` and `SLACK_APP_TOKEN`
|
||||
3. Ensure event subscriptions are configured (app_mention, message.im)
|
||||
|
||||
### WhatsApp QR code not appearing
|
||||
|
||||
1. Make sure Signal Desktop is closed (conflicts with baileys)
|
||||
2. Delete `~/.wwebjs_auth` if previously used different library
|
||||
3. Check no other WhatsApp Web sessions are active
|
||||
|
||||
## Example: Agent Setup Flow
|
||||
|
||||
For coding agents helping users set up LettaBot:
|
||||
|
||||
```bash
|
||||
# 1. Clone and build
|
||||
git clone https://github.com/letta-ai/lettabot.git
|
||||
cd lettabot
|
||||
npm install && npm run build && npm link
|
||||
|
||||
# 2. Get Letta API key
|
||||
# Guide user to app.letta.com → API Keys → Create Key
|
||||
|
||||
# 3. Get Telegram bot token
|
||||
# Guide user to @BotFather → /newbot → follow prompts
|
||||
|
||||
# 4. Set environment variables
|
||||
export LETTA_API_KEY="letta_..."
|
||||
export TELEGRAM_BOT_TOKEN="123456:ABC-DEF..."
|
||||
|
||||
# 5. Run non-interactive setup
|
||||
lettabot onboard --non-interactive
|
||||
|
||||
# 6. Start server
|
||||
lettabot server
|
||||
```
|
||||
|
||||
The agent can verify success by checking:
|
||||
- `lettabot server` output shows "Connected to Telegram"
|
||||
- Config file exists at `~/.config/lettabot/config.yaml`
|
||||
- User can message bot on Telegram
|
||||
|
||||
## Self-Hosted Letta
|
||||
|
||||
To use a self-hosted Letta server:
|
||||
|
||||
```bash
|
||||
# Run Letta Docker
|
||||
docker run -v ~/.letta/.persist/pgdata:/var/lib/postgresql/data \
|
||||
-p 8283:8283 \
|
||||
-e OPENAI_API_KEY="your_openai_api_key" \
|
||||
letta/letta:latest
|
||||
|
||||
# Configure LettaBot
|
||||
export LETTA_BASE_URL="http://localhost:8283"
|
||||
export LETTA_API_KEY="sk-..." # From Letta admin panel
|
||||
|
||||
lettabot onboard --non-interactive
|
||||
```
|
||||
|
||||
## Skills Integration
|
||||
|
||||
LettaBot supports loading skills from:
|
||||
- **Clawdhub** ([clawdhub.com](https://clawdhub.com))
|
||||
- **skills.sh** repositories
|
||||
- Local `.skills/` directory
|
||||
|
||||
```bash
|
||||
# Install skill from Clawdhub
|
||||
npx molthub@latest install sonoscli
|
||||
|
||||
# Connect to LettaBot
|
||||
lettabot skills
|
||||
# Space to toggle, Enter to confirm
|
||||
|
||||
# Skills will be available to agent
|
||||
```
|
||||
@@ -206,7 +206,8 @@ async function main() {
|
||||
case 'onboard':
|
||||
case 'setup':
|
||||
case 'init':
|
||||
await onboard();
|
||||
const nonInteractive = args.includes('--non-interactive') || args.includes('-n');
|
||||
await onboard({ nonInteractive });
|
||||
break;
|
||||
|
||||
case 'server':
|
||||
|
||||
156
src/onboard.ts
156
src/onboard.ts
@@ -9,6 +9,119 @@ import * as p from '@clack/prompts';
|
||||
import { saveConfig, syncProviders } from './config/index.js';
|
||||
import type { LettaBotConfig, ProviderConfig } from './config/types.js';
|
||||
|
||||
// ============================================================================
|
||||
// Non-Interactive Helpers
|
||||
// ============================================================================
|
||||
|
||||
function readConfigFromEnv(existingConfig: any): any {
|
||||
return {
|
||||
baseUrl: process.env.LETTA_BASE_URL || existingConfig.server?.baseUrl || 'https://api.letta.com',
|
||||
apiKey: process.env.LETTA_API_KEY || existingConfig.server?.apiKey,
|
||||
agentId: process.env.LETTA_AGENT_ID || existingConfig.agent?.id,
|
||||
agentName: process.env.LETTA_AGENT_NAME || existingConfig.agent?.name || 'lettabot',
|
||||
model: process.env.LETTA_MODEL || existingConfig.agent?.model || 'claude-sonnet-4',
|
||||
|
||||
telegram: {
|
||||
enabled: !!process.env.TELEGRAM_BOT_TOKEN,
|
||||
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,
|
||||
},
|
||||
|
||||
slack: {
|
||||
enabled: !!(process.env.SLACK_BOT_TOKEN && process.env.SLACK_APP_TOKEN),
|
||||
botToken: process.env.SLACK_BOT_TOKEN || existingConfig.channels?.slack?.botToken,
|
||||
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,
|
||||
},
|
||||
|
||||
discord: {
|
||||
enabled: !!process.env.DISCORD_BOT_TOKEN,
|
||||
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,
|
||||
},
|
||||
|
||||
whatsapp: {
|
||||
enabled: process.env.WHATSAPP_ENABLED === 'true' || !!existingConfig.channels?.whatsapp?.enabled,
|
||||
selfChat: process.env.WHATSAPP_SELF_CHAT === 'true' || !!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,
|
||||
},
|
||||
|
||||
signal: {
|
||||
enabled: !!process.env.SIGNAL_PHONE_NUMBER,
|
||||
phoneNumber: process.env.SIGNAL_PHONE_NUMBER || existingConfig.channels?.signal?.phoneNumber,
|
||||
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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function saveConfigFromEnv(config: any, configPath: string): Promise<void> {
|
||||
const { saveConfig } = await import('./config/index.js');
|
||||
|
||||
const lettabotConfig: LettaBotConfig = {
|
||||
server: {
|
||||
mode: config.baseUrl?.includes('localhost') ? 'selfhosted' : 'cloud',
|
||||
baseUrl: config.baseUrl,
|
||||
apiKey: config.apiKey,
|
||||
},
|
||||
agent: {
|
||||
id: config.agentId,
|
||||
name: config.agentName,
|
||||
model: config.model,
|
||||
},
|
||||
channels: {
|
||||
telegram: config.telegram.enabled ? {
|
||||
enabled: true,
|
||||
token: config.telegram.botToken,
|
||||
dmPolicy: config.telegram.dmPolicy,
|
||||
allowedUsers: config.telegram.allowedUsers,
|
||||
} : { enabled: false },
|
||||
|
||||
slack: config.slack.enabled ? {
|
||||
enabled: true,
|
||||
botToken: config.slack.botToken,
|
||||
appToken: config.slack.appToken,
|
||||
allowedUsers: config.slack.allowedUsers,
|
||||
} : { enabled: false },
|
||||
|
||||
discord: config.discord.enabled ? {
|
||||
enabled: true,
|
||||
token: config.discord.botToken,
|
||||
dmPolicy: config.discord.dmPolicy,
|
||||
allowedUsers: config.discord.allowedUsers,
|
||||
} : { enabled: false },
|
||||
|
||||
whatsapp: config.whatsapp.enabled ? {
|
||||
enabled: true,
|
||||
selfChat: config.whatsapp.selfChat,
|
||||
dmPolicy: config.whatsapp.dmPolicy,
|
||||
allowedUsers: config.whatsapp.allowedUsers,
|
||||
} : { enabled: false },
|
||||
|
||||
signal: config.signal.enabled ? {
|
||||
enabled: true,
|
||||
phone: config.signal.phoneNumber,
|
||||
selfChat: config.signal.selfChat,
|
||||
dmPolicy: config.signal.dmPolicy,
|
||||
allowedUsers: config.signal.allowedUsers,
|
||||
} : { enabled: false },
|
||||
},
|
||||
features: {
|
||||
cron: false,
|
||||
heartbeat: {
|
||||
enabled: false,
|
||||
intervalMin: 60,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
saveConfig(lettabotConfig);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Config Types
|
||||
// ============================================================================
|
||||
@@ -1173,7 +1286,8 @@ async function reviewLoop(config: OnboardConfig, env: Record<string, string>): P
|
||||
// Main Onboard Function
|
||||
// ============================================================================
|
||||
|
||||
export async function onboard(): Promise<void> {
|
||||
export async function onboard(options?: { nonInteractive?: boolean }): Promise<void> {
|
||||
const nonInteractive = options?.nonInteractive || false;
|
||||
// Temporary storage for wizard values
|
||||
const env: Record<string, string> = {};
|
||||
|
||||
@@ -1183,6 +1297,46 @@ export async function onboard(): Promise<void> {
|
||||
const configPath = resolveConfigPath();
|
||||
const hasExistingConfig = existsSync(configPath);
|
||||
|
||||
// Non-interactive mode: read all config from env vars
|
||||
if (nonInteractive) {
|
||||
console.log('🤖 LettaBot Non-Interactive Setup\n');
|
||||
console.log('Reading configuration from environment variables...\n');
|
||||
|
||||
const config = readConfigFromEnv(existingConfig);
|
||||
|
||||
// Validate required fields
|
||||
if (!config.baseUrl) {
|
||||
console.error('❌ Error: LETTA_BASE_URL is required');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!config.apiKey && !config.baseUrl?.includes('localhost')) {
|
||||
console.error('❌ Error: LETTA_API_KEY is required (or use self-hosted with LETTA_BASE_URL)');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Test server connection
|
||||
console.log(`Connecting to ${config.baseUrl}...`);
|
||||
try {
|
||||
const res = await fetch(`${config.baseUrl}/v1/health`, { signal: AbortSignal.timeout(5000) });
|
||||
if (res.ok) {
|
||||
console.log('✅ Connected to server\n');
|
||||
} else {
|
||||
console.error(`❌ Server returned status ${res.status}`);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`❌ Could not connect to ${config.baseUrl}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Save config and exit
|
||||
await saveConfigFromEnv(config, configPath);
|
||||
console.log(`✅ Configuration saved to ${configPath}\n`);
|
||||
console.log('Run "lettabot server" to start the bot.');
|
||||
return;
|
||||
}
|
||||
|
||||
p.intro('🤖 LettaBot Setup');
|
||||
|
||||
if (hasExistingConfig) {
|
||||
|
||||
@@ -85,13 +85,14 @@ async function stepCreateApp(): Promise<boolean> {
|
||||
p.log.step('Step 1/3: Create Slack App from Manifest');
|
||||
|
||||
// Inline manifest for Socket Mode configuration
|
||||
const appName = process.env.SLACK_APP_NAME || process.env.LETTA_AGENT_NAME || 'LettaBot';
|
||||
const manifest = `display_information:
|
||||
name: LettaBot
|
||||
name: ${appName}
|
||||
description: AI assistant with Socket Mode for real-time conversations
|
||||
background_color: "#2c2d30"
|
||||
features:
|
||||
bot_user:
|
||||
display_name: LettaBot
|
||||
display_name: ${appName}
|
||||
always_online: false
|
||||
oauth_config:
|
||||
scopes:
|
||||
|
||||
Reference in New Issue
Block a user