fix(onboard): remove fragile numeric channel dispatch
Use enum-backed channel menu dispatch to prevent duplicated match-arm indices and unreachable-pattern warnings (issue #913). Also switch OpenAI native tool spec parsing to owned serde structs so tool-schema validation compiles.
This commit is contained in:
parent
ef82c7dbcd
commit
4531c342f5
2 changed files with 159 additions and 113 deletions
|
|
@ -26,6 +26,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- `enc:` prefix for encrypted secrets — Use `enc2:` (ChaCha20-Poly1305) instead.
|
||||
Legacy values are still decrypted for backward compatibility but should be migrated.
|
||||
|
||||
### Fixed
|
||||
- **Onboarding channel menu dispatch** now uses an enum-backed selector instead of hard-coded
|
||||
numeric match arms, preventing duplicated pattern arms and related `unreachable pattern`
|
||||
compiler warnings in `src/onboard/wizard.rs`.
|
||||
- **OpenAI native tool spec parsing** now uses owned serializable/deserializable structs,
|
||||
fixing a compile-time type mismatch when validating tool schemas before API calls.
|
||||
|
||||
## [0.1.0] - 2026-02-13
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -2590,10 +2590,43 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
println!();
|
||||
|
||||
let mut config = ChannelsConfig::default();
|
||||
#[derive(Clone, Copy)]
|
||||
enum ChannelMenuChoice {
|
||||
Telegram,
|
||||
Discord,
|
||||
Slack,
|
||||
IMessage,
|
||||
Matrix,
|
||||
WhatsApp,
|
||||
Linq,
|
||||
Irc,
|
||||
Webhook,
|
||||
DingTalk,
|
||||
QqOfficial,
|
||||
LarkFeishu,
|
||||
Done,
|
||||
}
|
||||
let menu_choices = [
|
||||
ChannelMenuChoice::Telegram,
|
||||
ChannelMenuChoice::Discord,
|
||||
ChannelMenuChoice::Slack,
|
||||
ChannelMenuChoice::IMessage,
|
||||
ChannelMenuChoice::Matrix,
|
||||
ChannelMenuChoice::WhatsApp,
|
||||
ChannelMenuChoice::Linq,
|
||||
ChannelMenuChoice::Irc,
|
||||
ChannelMenuChoice::Webhook,
|
||||
ChannelMenuChoice::DingTalk,
|
||||
ChannelMenuChoice::QqOfficial,
|
||||
ChannelMenuChoice::LarkFeishu,
|
||||
ChannelMenuChoice::Done,
|
||||
];
|
||||
|
||||
loop {
|
||||
let options = vec![
|
||||
format!(
|
||||
let options: Vec<String> = menu_choices
|
||||
.iter()
|
||||
.map(|choice| match choice {
|
||||
ChannelMenuChoice::Telegram => format!(
|
||||
"Telegram {}",
|
||||
if config.telegram.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2601,7 +2634,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— connect your bot"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::Discord => format!(
|
||||
"Discord {}",
|
||||
if config.discord.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2609,7 +2642,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— connect your bot"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::Slack => format!(
|
||||
"Slack {}",
|
||||
if config.slack.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2617,7 +2650,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— connect your bot"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::IMessage => format!(
|
||||
"iMessage {}",
|
||||
if config.imessage.is_some() {
|
||||
"✅ configured"
|
||||
|
|
@ -2625,7 +2658,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— macOS only"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::Matrix => format!(
|
||||
"Matrix {}",
|
||||
if config.matrix.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2633,7 +2666,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— self-hosted chat"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::WhatsApp => format!(
|
||||
"WhatsApp {}",
|
||||
if config.whatsapp.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2641,7 +2674,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— Business Cloud API"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::Linq => format!(
|
||||
"Linq {}",
|
||||
if config.linq.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2649,7 +2682,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— iMessage/RCS/SMS via Linq API"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::Irc => format!(
|
||||
"IRC {}",
|
||||
if config.irc.is_some() {
|
||||
"✅ configured"
|
||||
|
|
@ -2657,7 +2690,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— IRC over TLS"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::Webhook => format!(
|
||||
"Webhook {}",
|
||||
if config.webhook.is_some() {
|
||||
"✅ configured"
|
||||
|
|
@ -2665,7 +2698,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— HTTP endpoint"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::DingTalk => format!(
|
||||
"DingTalk {}",
|
||||
if config.dingtalk.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2673,7 +2706,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— DingTalk Stream Mode"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::QqOfficial => format!(
|
||||
"QQ Official {}",
|
||||
if config.qq.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2681,7 +2714,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— Tencent QQ Bot"
|
||||
}
|
||||
),
|
||||
format!(
|
||||
ChannelMenuChoice::LarkFeishu => format!(
|
||||
"Lark/Feishu {}",
|
||||
if config.lark.is_some() {
|
||||
"✅ connected"
|
||||
|
|
@ -2689,17 +2722,23 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
"— Lark/Feishu Bot"
|
||||
}
|
||||
),
|
||||
"Done — finish setup".to_string(),
|
||||
];
|
||||
ChannelMenuChoice::Done => "Done — finish setup".to_string(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let choice = Select::new()
|
||||
let selection = Select::new()
|
||||
.with_prompt(" Connect a channel (or Done to continue)")
|
||||
.items(&options)
|
||||
.default(options.len() - 1)
|
||||
.interact()?;
|
||||
|
||||
let choice = menu_choices
|
||||
.get(selection)
|
||||
.copied()
|
||||
.unwrap_or(ChannelMenuChoice::Done);
|
||||
|
||||
match choice {
|
||||
0 => {
|
||||
ChannelMenuChoice::Telegram => {
|
||||
// ── Telegram ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -2797,7 +2836,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
mention_only: false,
|
||||
});
|
||||
}
|
||||
1 => {
|
||||
ChannelMenuChoice::Discord => {
|
||||
// ── Discord ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -2896,7 +2935,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
mention_only: false,
|
||||
});
|
||||
}
|
||||
2 => {
|
||||
ChannelMenuChoice::Slack => {
|
||||
// ── Slack ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3021,7 +3060,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
allowed_users,
|
||||
});
|
||||
}
|
||||
3 => {
|
||||
ChannelMenuChoice::IMessage => {
|
||||
// ── iMessage ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3065,7 +3104,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
style(&contacts_str).cyan()
|
||||
);
|
||||
}
|
||||
4 => {
|
||||
ChannelMenuChoice::Matrix => {
|
||||
// ── Matrix ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3177,7 +3216,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
allowed_users,
|
||||
});
|
||||
}
|
||||
5 => {
|
||||
ChannelMenuChoice::WhatsApp => {
|
||||
// ── WhatsApp ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3274,7 +3313,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
allowed_numbers,
|
||||
});
|
||||
}
|
||||
6 => {
|
||||
ChannelMenuChoice::Linq => {
|
||||
// ── Linq ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3366,7 +3405,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
allowed_senders,
|
||||
});
|
||||
}
|
||||
7 => {
|
||||
ChannelMenuChoice::Irc => {
|
||||
// ── IRC ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3505,7 +3544,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
verify_tls: Some(verify_tls),
|
||||
});
|
||||
}
|
||||
8 => {
|
||||
ChannelMenuChoice::Webhook => {
|
||||
// ── Webhook ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3538,7 +3577,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
style(&port).cyan()
|
||||
);
|
||||
}
|
||||
9 => {
|
||||
ChannelMenuChoice::DingTalk => {
|
||||
// ── DingTalk ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3608,7 +3647,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
allowed_users,
|
||||
});
|
||||
}
|
||||
10 => {
|
||||
ChannelMenuChoice::QqOfficial => {
|
||||
// ── QQ Official ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3684,7 +3723,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
allowed_users,
|
||||
});
|
||||
}
|
||||
11 => {
|
||||
ChannelMenuChoice::LarkFeishu => {
|
||||
// ── Lark/Feishu ──
|
||||
println!();
|
||||
println!(
|
||||
|
|
@ -3871,7 +3910,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
|||
port,
|
||||
});
|
||||
}
|
||||
_ => break, // Done
|
||||
ChannelMenuChoice::Done => break,
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue