feat(channels): add napcat/onebot onboarding and config UI
This commit is contained in:
parent
b21a1a91ac
commit
31ca8c2fed
@ -437,13 +437,14 @@ Examples:
|
||||
#[arg(long, value_enum, default_value_t = QuotaFormat::Text)]
|
||||
format: QuotaFormat,
|
||||
},
|
||||
/// Manage channels (telegram, discord, slack, github)
|
||||
/// Manage channels (telegram, discord, slack, qq, napcat, and more)
|
||||
#[command(long_about = "\
|
||||
Manage communication channels.
|
||||
|
||||
Add, remove, list, and health-check channels that connect ZeroClaw \
|
||||
to messaging platforms. Supported channel types: telegram, discord, \
|
||||
slack, whatsapp, github, matrix, imessage, email.
|
||||
slack, mattermost, whatsapp, matrix, signal, qq, napcat, \
|
||||
lark, feishu, dingtalk, github, nextcloud, irc, imessage, email.
|
||||
|
||||
Examples:
|
||||
zeroclaw channel list
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::config::schema::{
|
||||
default_nostr_relays, DingTalkConfig, IrcConfig, LarkReceiveMode, LinqConfig,
|
||||
default_nostr_relays, DingTalkConfig, IrcConfig, LarkReceiveMode, LinqConfig, NapcatConfig,
|
||||
NextcloudTalkConfig, NostrConfig, ProgressMode, QQConfig, QQEnvironment, QQReceiveMode,
|
||||
SignalConfig, StreamMode, WhatsAppConfig,
|
||||
};
|
||||
@ -4275,6 +4275,7 @@ enum ChannelMenuChoice {
|
||||
NextcloudTalk,
|
||||
DingTalk,
|
||||
QqOfficial,
|
||||
Napcat,
|
||||
LarkFeishu,
|
||||
Nostr,
|
||||
Done,
|
||||
@ -4294,6 +4295,7 @@ const CHANNEL_MENU_CHOICES: &[ChannelMenuChoice] = &[
|
||||
ChannelMenuChoice::NextcloudTalk,
|
||||
ChannelMenuChoice::DingTalk,
|
||||
ChannelMenuChoice::QqOfficial,
|
||||
ChannelMenuChoice::Napcat,
|
||||
ChannelMenuChoice::LarkFeishu,
|
||||
ChannelMenuChoice::Nostr,
|
||||
ChannelMenuChoice::Done,
|
||||
@ -4420,6 +4422,14 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
||||
"— Tencent QQ Bot"
|
||||
}
|
||||
),
|
||||
ChannelMenuChoice::Napcat => format!(
|
||||
"Napcat/OneBot {}",
|
||||
if config.napcat.is_some() {
|
||||
"✅ connected"
|
||||
} else {
|
||||
"— QQ via OneBot v11"
|
||||
}
|
||||
),
|
||||
ChannelMenuChoice::LarkFeishu => format!(
|
||||
"Lark/Feishu {}",
|
||||
if config.lark.is_some() {
|
||||
@ -5716,6 +5726,62 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
||||
environment,
|
||||
});
|
||||
}
|
||||
ChannelMenuChoice::Napcat => {
|
||||
// ── Napcat / OneBot ──
|
||||
println!();
|
||||
println!(
|
||||
" {} {}",
|
||||
style("Napcat / OneBot Setup").white().bold(),
|
||||
style("— QQ via OneBot v11 (Napcat)").dim()
|
||||
);
|
||||
print_bullet("1. Start your Napcat/OneBot gateway");
|
||||
print_bullet("2. Enable OneBot v11 WebSocket endpoint");
|
||||
print_bullet("3. Paste the WebSocket URL and optional token below");
|
||||
println!();
|
||||
|
||||
let websocket_url: String = Input::new()
|
||||
.with_prompt(" WebSocket URL")
|
||||
.default("ws://127.0.0.1:3001".into())
|
||||
.interact_text()?;
|
||||
let websocket_url = websocket_url.trim().to_string();
|
||||
if websocket_url.is_empty() {
|
||||
println!(" {} Skipped", style("→").dim());
|
||||
continue;
|
||||
}
|
||||
|
||||
let api_base_url: String = Input::new()
|
||||
.with_prompt(" HTTP API base URL (optional, Enter to auto-derive)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
|
||||
let access_token: String = Input::new()
|
||||
.with_prompt(" Access token (optional)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
|
||||
let users_str: String = Input::new()
|
||||
.with_prompt(" Allowed QQ user IDs (comma-separated, '*' for all)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
let allowed_users: Vec<String> = users_str
|
||||
.split(',')
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
|
||||
config.napcat = Some(NapcatConfig {
|
||||
websocket_url,
|
||||
api_base_url: api_base_url.trim().to_string(),
|
||||
access_token: if access_token.trim().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(access_token.trim().to_string())
|
||||
},
|
||||
allowed_users,
|
||||
});
|
||||
|
||||
println!(" {} Napcat configured", style("✅").green().bold());
|
||||
}
|
||||
ChannelMenuChoice::LarkFeishu => {
|
||||
// ── Lark/Feishu ──
|
||||
println!();
|
||||
@ -8789,14 +8855,15 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn channel_menu_choices_include_signal_nextcloud_and_dingtalk() {
|
||||
fn channel_menu_choices_include_signal_nextcloud_dingtalk_and_napcat() {
|
||||
assert!(channel_menu_choices().contains(&ChannelMenuChoice::Signal));
|
||||
assert!(channel_menu_choices().contains(&ChannelMenuChoice::NextcloudTalk));
|
||||
assert!(channel_menu_choices().contains(&ChannelMenuChoice::DingTalk));
|
||||
assert!(channel_menu_choices().contains(&ChannelMenuChoice::Napcat));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn launchable_channels_include_signal_mattermost_qq_nextcloud_and_dingtalk() {
|
||||
fn launchable_channels_include_signal_mattermost_qq_nextcloud_dingtalk_and_napcat() {
|
||||
let mut channels = ChannelsConfig::default();
|
||||
assert!(!has_launchable_channels(&channels));
|
||||
|
||||
@ -8848,5 +8915,14 @@ mod tests {
|
||||
allowed_users: vec!["*".into()],
|
||||
});
|
||||
assert!(has_launchable_channels(&channels));
|
||||
|
||||
channels.dingtalk = None;
|
||||
channels.napcat = Some(crate::config::schema::NapcatConfig {
|
||||
websocket_url: "ws://127.0.0.1:3001".into(),
|
||||
api_base_url: String::new(),
|
||||
access_token: None,
|
||||
allowed_users: vec!["*".into()],
|
||||
});
|
||||
assert!(has_launchable_channels(&channels));
|
||||
}
|
||||
}
|
||||
|
||||
@ -640,6 +640,22 @@ export const CONFIG_SECTIONS: SectionDef[] = [
|
||||
],
|
||||
},
|
||||
|
||||
// ── Napcat (OneBot) ───────────────────────────────────────────────
|
||||
{
|
||||
path: 'channels_config.napcat',
|
||||
category: 'channels',
|
||||
title: 'Napcat (OneBot)',
|
||||
description: 'QQ via OneBot v11 (Napcat)',
|
||||
icon: MessageCircle,
|
||||
defaultCollapsed: true,
|
||||
fields: [
|
||||
{ key: 'websocket_url', label: 'WebSocket URL', type: 'text', description: 'e.g. ws://127.0.0.1:3001' },
|
||||
{ key: 'api_base_url', label: 'HTTP API Base URL', type: 'text', description: 'Optional. Leave empty to auto-derive from websocket_url' },
|
||||
{ key: 'access_token', label: 'Access Token', type: 'password', sensitive: true, description: 'Optional bearer token for Napcat/OneBot API' },
|
||||
{ key: 'allowed_users', label: 'Allowed Users', type: 'tag-list', tagPlaceholder: "e.g. 10001 or '*'" },
|
||||
],
|
||||
},
|
||||
|
||||
// ── Memory ────────────────────────────────────────────────────────
|
||||
{
|
||||
path: 'memory',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user