Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ cc-switch prompts list # List prompt presets
cc-switch prompts current # Show current active prompt
cc-switch prompts activate <id> # Activate prompt
cc-switch prompts deactivate # Deactivate current active prompt
cc-switch prompts create # Create new prompt preset
cc-switch prompts create [name] # Create a prompt preset, optionally naming it up front
cc-switch prompts rename <id> [name] # Rename prompt preset, interactive if name is omitted
cc-switch prompts edit <id> # Edit prompt preset
cc-switch prompts show <id> # Display full content
cc-switch prompts delete <id> # Delete prompt
Expand Down
3 changes: 2 additions & 1 deletion README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@ cc-switch prompts list # 列出提示词预设
cc-switch prompts current # 显示当前活动提示词
cc-switch prompts activate <id> # 激活提示词
cc-switch prompts deactivate # 停用当前激活的提示词
cc-switch prompts create # 创建新提示词预设
cc-switch prompts create [name] # 创建新提示词预设,可直接指定名称
cc-switch prompts rename <id> [name] # 重命名提示词预设,不传名称时进入交互
cc-switch prompts edit <id> # 编辑提示词预设
cc-switch prompts show <id> # 显示完整内容
cc-switch prompts delete <id> # 删除提示词
Expand Down
96 changes: 72 additions & 24 deletions src-tauri/src/cli/commands/prompts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use clap::Subcommand;
use crate::app_config::AppType;
use crate::cli::ui::{create_table, highlight, info, success};
use crate::error::AppError;
use crate::prompt::Prompt;
use crate::services::PromptService;
use crate::store::AppState;

Expand All @@ -21,12 +20,22 @@ pub enum PromptsCommand {
/// Deactivate the current active prompt
Deactivate,
/// Create a new prompt preset
Create,
Create {
/// Prompt preset name
name: Option<String>,
},
/// Edit a prompt preset
Edit {
/// Prompt preset ID
id: String,
},
/// Rename a prompt preset
Rename {
/// Prompt preset ID
id: String,
/// New prompt name
name: Option<String>,
},
/// Delete a prompt preset
Delete {
/// Prompt preset ID
Expand All @@ -47,8 +56,9 @@ pub fn execute(cmd: PromptsCommand, app: Option<AppType>) -> Result<(), AppError
PromptsCommand::Current => show_current(app_type),
PromptsCommand::Activate { id } => activate_prompt(app_type, &id),
PromptsCommand::Deactivate => deactivate_prompt(app_type),
PromptsCommand::Create => create_prompt(app_type),
PromptsCommand::Create { name } => create_prompt(app_type, name),
PromptsCommand::Edit { id } => edit_prompt(app_type, &id),
PromptsCommand::Rename { id, name } => rename_prompt(app_type, &id, name),
PromptsCommand::Delete { id } => delete_prompt(app_type, &id),
PromptsCommand::Show { id } => show_prompt(app_type, &id),
}
Expand Down Expand Up @@ -296,36 +306,37 @@ fn show_prompt(app_type: AppType, id: &str) -> Result<(), AppError> {
Ok(())
}

fn create_prompt(_app_type: AppType) -> Result<(), AppError> {
fn create_prompt(app_type: AppType, name: Option<String>) -> Result<(), AppError> {
let state = get_state()?;
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as i64;
let id = format!("prompt-{timestamp}");
let default_name = format!("Prompt {}", chrono::Local::now().format("%Y-%m-%d %H:%M"));
let name = match name {
Some(name) => name,
None => inquire::Text::new("Prompt name:")
.with_initial_value(&default_name)
.prompt()
.map_err(|e| AppError::Message(format!("Prompt failed: {}", e)))?,
};
let trimmed_name = name.trim();
if trimmed_name.is_empty() {
return Err(AppError::InvalidInput(
"Prompt preset name cannot be empty".to_string(),
));
}

let name = format!("Prompt {}", chrono::Local::now().format("%Y-%m-%d %H:%M"));
let initial = "# Write your prompt here\n";

println!("{}", highlight("Create New Prompt Preset"));
println!("{}", info("Opening external editor..."));

let edited = crate::cli::editor::open_external_editor(initial)?;
let prompt = PromptService::create_prompt(&state, app_type.clone(), trimmed_name, &edited)?;

let content = edited.trim_end().to_string();
let prompt = Prompt {
id: id.clone(),
name,
content,
description: None,
enabled: false,
created_at: Some(timestamp),
updated_at: Some(timestamp),
};

PromptService::upsert_prompt(&state, _app_type.clone(), &id, prompt)?;

println!("{}", success(&format!("✓ Created prompt preset '{id}'")));
println!(
"{}",
success(&format!("✓ Created prompt preset '{}'", prompt.id))
);
println!("{}", info(&format!(" Name: {}", prompt.name)));
println!("{}", info(&format!(" Application: {}", app_type.as_str())));
println!(
"{}",
info("Tip: Use 'cc-switch prompts list' to view all presets.")
Expand Down Expand Up @@ -399,3 +410,40 @@ fn edit_prompt(_app_type: AppType, id: &str) -> Result<(), AppError> {
println!("{}", success(&format!("✓ Updated prompt preset '{id}'")));
Ok(())
}

fn rename_prompt(app_type: AppType, id: &str, name: Option<String>) -> Result<(), AppError> {
let state = get_state()?;
let prompts = PromptService::get_prompts(&state, app_type.clone())?;
let Some(prompt) = prompts.get(id) else {
return Err(AppError::InvalidInput(format!(
"Prompt preset '{id}' not found"
)));
};

let new_name = match name {
Some(name) => name,
None => inquire::Text::new("New prompt name:")
.with_initial_value(&prompt.name)
.prompt()
.map_err(|e| AppError::Message(format!("Prompt failed: {}", e)))?,
};

let trimmed = new_name.trim();
if trimmed.is_empty() {
return Err(AppError::InvalidInput(
"Prompt preset name cannot be empty".to_string(),
));
}

if trimmed == prompt.name {
println!("{}", info("No changes detected."));
return Ok(());
}

PromptService::rename_prompt(&state, app_type.clone(), id, trimmed)?;

println!("{}", success(&format!("✓ Renamed prompt preset '{id}'")));
println!("{}", info(&format!(" Name: {}", trimmed)));
println!("{}", info(&format!(" Application: {}", app_type.as_str())));
Ok(())
}
72 changes: 68 additions & 4 deletions src-tauri/src/cli/i18n.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,9 +509,9 @@ pub mod texts {

pub fn tui_footer_action_keys_prompts() -> &'static str {
if is_chinese() {
"[ ] 切换应用 Enter 查看 a 激活 x 取消激活 e 编辑 d 删除 / 过滤 Esc 返回 ? 帮助"
"[ ] 切换应用 c 新建 r 刷新 Enter 查看 a 激活 x 取消激活 n 重命名 e 编辑 d 删除 / 过滤 Esc 返回 ? 帮助"
} else {
"[ ] switch app Enter view a activate x deactivate e edit d delete / filter Esc back ? help"
"[ ] switch app c create r refresh Enter view a activate x deactivate n rename e edit d delete / filter Esc back ? help"
}
}

Expand Down Expand Up @@ -565,9 +565,9 @@ pub mod texts {

pub fn tui_help_text() -> &'static str {
if is_chinese() {
"[ ] 切换应用\n←→ 切换菜单/内容焦点\n↑↓ 移动\n/ 过滤\nEsc 返回\n? 显示/关闭帮助\n\n页面快捷键(在页面内容区顶部显示):\n- 供应商:Enter 详情,s 切换/添加移除,a 添加,e 编辑,d 删除,t 测速,c 健康检查\n- 供应商详情:s 切换/添加移除,e 编辑,t 测速,c 健康检查\n- MCP:x 启用/禁用(当前应用),m 选择应用,a 添加,e 编辑,i 导入已有,d 删除\n- 提示词:Enter 查看,a 激活,x 取消激活(当前),e 编辑,d 删除\n- 技能:Enter 详情,x 启用/禁用(当前应用),m 选择应用,d 卸载,i 导入已有\n- 配置:Enter 打开/执行,e 编辑片段\n- 设置:Enter 应用"
"[ ] 切换应用\n←→ 切换菜单/内容焦点\n↑↓ 移动\n/ 过滤\nEsc 返回\n? 显示/关闭帮助\n\n页面快捷键(在页面内容区顶部显示):\n- 供应商:Enter 详情,s 切换/添加移除,a 添加,e 编辑,d 删除,t 测速,c 健康检查\n- 供应商详情:s 切换/添加移除,e 编辑,t 测速,c 健康检查\n- MCP:x 启用/禁用(当前应用),m 选择应用,a 添加,e 编辑,i 导入已有,d 删除\n- 提示词:c 新建,r 刷新,Enter 查看,a 激活,x 取消激活(当前),n 重命名,e 编辑,d 删除\n- 技能:Enter 详情,x 启用/禁用(当前应用),m 选择应用,d 卸载,i 导入已有\n- 配置:Enter 打开/执行,e 编辑片段\n- 设置:Enter 应用"
} else {
"[ ] switch app\n←→ focus menu/content\n↑↓ move\n/ filter\nEsc back\n? toggle help\n\nPage keys (shown at the top of each page):\n- Providers: Enter details, s switch/add-remove, a add, e edit, d delete, t speedtest, c stream check\n- Provider Detail: s switch/add-remove, e edit, t speedtest, c stream check\n- MCP: x toggle current, m select apps, a add, e edit, i import existing, d delete\n- Prompts: Enter view, a activate, x deactivate active, e edit, d delete\n- Skills: Enter details, x toggle current, m select apps, d uninstall, i import existing\n- Config: Enter open/run, e edit snippet\n- Settings: Enter apply"
"[ ] switch app\n←→ focus menu/content\n↑↓ move\n/ filter\nEsc back\n? toggle help\n\nPage keys (shown at the top of each page):\n- Providers: Enter details, s switch/add-remove, a add, e edit, d delete, t speedtest, c stream check\n- Provider Detail: s switch/add-remove, e edit, t speedtest, c stream check\n- MCP: x toggle current, m select apps, a add, e edit, i import existing, d delete\n- Prompts: c create, r refresh, Enter view, a activate, x deactivate active, n rename, e edit, d delete\n- Skills: Enter details, x toggle current, m select apps, d uninstall, i import existing\n- Config: Enter open/run, e edit snippet\n- Settings: Enter apply"
}
}

Expand Down Expand Up @@ -2450,6 +2450,14 @@ pub mod texts {
}
}

pub fn tui_key_rename() -> &'static str {
if is_chinese() {
"重命名"
} else {
"rename"
}
}

pub fn tui_key_apply() -> &'static str {
if is_chinese() {
"应用"
Expand Down Expand Up @@ -4499,6 +4507,38 @@ pub mod texts {
}
}

pub fn tui_prompt_rename_title() -> &'static str {
if is_chinese() {
"重命名提示词"
} else {
"Rename Prompt"
}
}

pub fn tui_prompt_create_title() -> &'static str {
if is_chinese() {
"创建提示词"
} else {
"Create Prompt"
}
}

pub fn tui_prompt_create_prompt() -> &'static str {
if is_chinese() {
"输入提示词名称:"
} else {
"Enter a prompt name:"
}
}

pub fn tui_prompt_rename_prompt() -> &'static str {
if is_chinese() {
"输入新的提示词名称:"
} else {
"Enter a new prompt name:"
}
}

pub fn tui_toast_prompt_no_active_to_deactivate() -> &'static str {
if is_chinese() {
"没有可停用的活动提示词。"
Expand Down Expand Up @@ -4547,6 +4587,14 @@ pub mod texts {
}
}

pub fn tui_toast_prompt_name_empty() -> &'static str {
if is_chinese() {
"提示词名称不能为空。"
} else {
"Prompt name cannot be empty."
}
}

pub fn tui_toast_prompt_not_found(id: &str) -> String {
if is_chinese() {
format!("未找到提示词:{}", id)
Expand Down Expand Up @@ -5382,6 +5430,22 @@ pub mod texts {
}
}

pub fn tui_toast_prompt_created() -> &'static str {
if is_chinese() {
"提示词已创建。"
} else {
"Prompt created."
}
}

pub fn tui_toast_prompt_renamed() -> &'static str {
if is_chinese() {
"提示词已重命名。"
} else {
"Prompt renamed."
}
}

pub fn tui_toast_exported_to(path: &str) -> String {
if is_chinese() {
format!("已导出到 {}", path)
Expand Down
40 changes: 40 additions & 0 deletions src-tauri/src/cli/i18n/texts/config_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,38 @@ pub fn tui_prompt_title(name: &str) -> String {
}
}

pub fn tui_prompt_rename_title() -> &'static str {
if is_chinese() {
"重命名提示词"
} else {
"Rename Prompt"
}
}

pub fn tui_prompt_create_title() -> &'static str {
if is_chinese() {
"创建提示词"
} else {
"Create Prompt"
}
}

pub fn tui_prompt_create_prompt() -> &'static str {
if is_chinese() {
"输入提示词名称:"
} else {
"Enter a prompt name:"
}
}

pub fn tui_prompt_rename_prompt() -> &'static str {
if is_chinese() {
"输入新的提示词名称:"
} else {
"Enter a new prompt name:"
}
}

pub fn tui_toast_prompt_no_active_to_deactivate() -> &'static str {
if is_chinese() {
"没有可停用的活动提示词。"
Expand Down Expand Up @@ -840,6 +872,14 @@ pub fn tui_toast_prompt_edit_finished() -> &'static str {
}
}

pub fn tui_toast_prompt_name_empty() -> &'static str {
if is_chinese() {
"提示词名称不能为空。"
} else {
"Prompt name cannot be empty."
}
}

pub fn tui_toast_prompt_not_found(id: &str) -> String {
if is_chinese() {
format!("未找到提示词:{}", id)
Expand Down
4 changes: 2 additions & 2 deletions src-tauri/src/cli/i18n/texts/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,9 @@ pub fn tui_help_title() -> &'static str {

pub fn tui_help_text() -> &'static str {
if is_chinese() {
"[ ] 切换应用\n←→ 切换菜单/内容焦点\n↑↓ 移动\n/ 过滤\nEsc 返回\n? 显示/关闭帮助\n\n页面快捷键(在页面内容区顶部显示):\n- 供应商:Enter 详情,s 切换,a 添加,e 编辑,d 删除,t 测速,c 健康检查\n- 供应商详情:s 切换,e 编辑,t 测速,c 健康检查\n- MCP:x 启用/禁用(当前应用),m 选择应用,a 添加,e 编辑,i 导入已有,d 删除\n- 提示词:Enter 查看,a 激活,x 取消激活(当前),e 编辑,d 删除\n- 技能:Enter 详情,x 启用/禁用(当前应用),m 选择应用,d 卸载,i 导入已有\n- 配置:Enter 打开/执行,e 编辑片段\n- 设置:Enter 应用"
"[ ] 切换应用\n←→ 切换菜单/内容焦点\n↑↓ 移动\n/ 过滤\nEsc 返回\n? 显示/关闭帮助\n\n页面快捷键(在页面内容区顶部显示):\n- 供应商:Enter 详情,s 切换,a 添加,e 编辑,d 删除,t 测速,c 健康检查\n- 供应商详情:s 切换,e 编辑,t 测速,c 健康检查\n- MCP:x 启用/禁用(当前应用),m 选择应用,a 添加,e 编辑,i 导入已有,d 删除\n- 提示词:c 新建,r 刷新,Enter 查看,a 激活,x 取消激活(当前),n 重命名,e 编辑,d 删除\n- 技能:Enter 详情,x 启用/禁用(当前应用),m 选择应用,d 卸载,i 导入已有\n- 配置:Enter 打开/执行,e 编辑片段\n- 设置:Enter 应用"
} else {
"[ ] switch app\n←→ focus menu/content\n↑↓ move\n/ filter\nEsc back\n? toggle help\n\nPage keys (shown at the top of each page):\n- Providers: Enter details, s switch, a add, e edit, d delete, t speedtest, c stream check\n- Provider Detail: s switch, e edit, t speedtest, c stream check\n- MCP: x toggle current, m select apps, a add, e edit, i import existing, d delete\n- Prompts: Enter view, a activate, x deactivate active, e edit, d delete\n- Skills: Enter details, x toggle current, m select apps, d uninstall, i import existing\n- Config: Enter open/run, e edit snippet\n- Settings: Enter apply"
"[ ] switch app\n←→ focus menu/content\n↑↓ move\n/ filter\nEsc back\n? toggle help\n\nPage keys (shown at the top of each page):\n- Providers: Enter details, s switch, a add, e edit, d delete, t speedtest, c stream check\n- Provider Detail: s switch, e edit, t speedtest, c stream check\n- MCP: x toggle current, m select apps, a add, e edit, i import existing, d delete\n- Prompts: c create, r refresh, Enter view, a activate, x deactivate active, n rename, e edit, d delete\n- Skills: Enter details, x toggle current, m select apps, d uninstall, i import existing\n- Config: Enter open/run, e edit snippet\n- Settings: Enter apply"
}
}

Expand Down
8 changes: 8 additions & 0 deletions src-tauri/src/cli/i18n/texts/providers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,14 @@ pub fn tui_key_refresh() -> &'static str {
}
}

pub fn tui_key_rename() -> &'static str {
if is_chinese() {
"重命名"
} else {
"rename"
}
}

pub fn tui_key_start_proxy() -> &'static str {
if is_chinese() {
"启动代理"
Expand Down
16 changes: 16 additions & 0 deletions src-tauri/src/cli/i18n/texts/toasts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,22 @@ pub fn tui_toast_prompt_deleted() -> &'static str {
}
}

pub fn tui_toast_prompt_created() -> &'static str {
if is_chinese() {
"提示词已创建。"
} else {
"Prompt created."
}
}

pub fn tui_toast_prompt_renamed() -> &'static str {
if is_chinese() {
"提示词已重命名。"
} else {
"Prompt renamed."
}
}

pub fn tui_toast_exported_to(path: &str) -> String {
if is_chinese() {
format!("已导出到 {}", path)
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub enum Commands {
#[command(subcommand)]
Mcp(commands::mcp::McpCommand),

/// Manage prompts (list, activate, edit)
/// Manage prompts (list, activate, create, rename, edit)
#[command(subcommand)]
Prompts(commands::prompts::PromptsCommand),

Expand Down
Loading
Loading