feat: 完成 rust cutover phase 8 收口
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,477 @@
|
||||
use clap::{Args, Parser, Subcommand, ValueEnum};
|
||||
use core_protocol::{InvocationKind, ToolExecutionMode};
|
||||
use mnote_cli::{
|
||||
plan_block_insert, plan_block_patch, plan_mindmap_get, plan_mindmap_op, plan_mindmap_put,
|
||||
plan_page_get, plan_page_save, plan_page_title, plan_search_blocks,
|
||||
plan_search_documents, plan_sidebar_dataset, plan_tool_run, render_plain_output, CliContext,
|
||||
CliError, CliJsonOutput,
|
||||
};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "mnote-cli")]
|
||||
#[command(about = "Phase 2 最小 CLI 协议冻结器", long_about = None)]
|
||||
struct Cli {
|
||||
#[command(flatten)]
|
||||
global: GlobalArgs,
|
||||
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug, Clone)]
|
||||
struct GlobalArgs {
|
||||
#[arg(long)]
|
||||
json: bool,
|
||||
|
||||
#[arg(long, default_value = "cli_user")]
|
||||
actor_id: String,
|
||||
|
||||
#[arg(long, default_value = "human")]
|
||||
actor_type: String,
|
||||
|
||||
#[arg(long)]
|
||||
session_id: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
reason: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
idempotency_key: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
validate_only: bool,
|
||||
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Commands {
|
||||
Page(PageCommand),
|
||||
Block(BlockCommand),
|
||||
Mindmap(MindmapCommand),
|
||||
Search(SearchCommand),
|
||||
Sidebar(SidebarCommand),
|
||||
Tool(ToolCommand),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct PageCommand {
|
||||
#[command(subcommand)]
|
||||
action: PageAction,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum PageAction {
|
||||
Get(PageGetArgs),
|
||||
Title(PageTitleArgs),
|
||||
Save(PageSaveArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct PageGetArgs {
|
||||
#[arg(long)]
|
||||
page_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
workspace_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct PageTitleArgs {
|
||||
#[arg(long)]
|
||||
page_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
workspace_id: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
title: String,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct PageSaveArgs {
|
||||
#[arg(long)]
|
||||
page_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
workspace_id: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
revision: Option<u64>,
|
||||
|
||||
#[arg(long)]
|
||||
content_json: String,
|
||||
|
||||
#[arg(long)]
|
||||
conflict_detection_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct BlockCommand {
|
||||
#[command(subcommand)]
|
||||
action: BlockAction,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum BlockAction {
|
||||
Insert(BlockInsertArgs),
|
||||
Patch(BlockPatchArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct BlockInsertArgs {
|
||||
#[arg(long)]
|
||||
workspace_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
page_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
content: String,
|
||||
|
||||
#[arg(long, default_value = "paragraph")]
|
||||
block_type: String,
|
||||
|
||||
#[arg(long)]
|
||||
parent_block_id: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
prev_block_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct BlockPatchArgs {
|
||||
#[arg(long)]
|
||||
page_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
block_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
workspace_id: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
revision: Option<u64>,
|
||||
|
||||
#[arg(long)]
|
||||
snapshot_json: String,
|
||||
|
||||
#[arg(long)]
|
||||
conflict_detection_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct MindmapCommand {
|
||||
#[command(subcommand)]
|
||||
action: MindmapAction,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum MindmapAction {
|
||||
Get(MindmapGetArgs),
|
||||
Put(MindmapPutArgs),
|
||||
Op(MindmapOpArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct MindmapGetArgs {
|
||||
#[arg(long)]
|
||||
document_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
mindmap_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
workspace_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct MindmapPutArgs {
|
||||
#[arg(long)]
|
||||
document_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
mindmap_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
workspace_id: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
data_json: String,
|
||||
|
||||
#[arg(long, default_value_t = false)]
|
||||
create_only: bool,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct MindmapOpArgs {
|
||||
#[arg(long)]
|
||||
document_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
mindmap_id: String,
|
||||
|
||||
#[arg(long)]
|
||||
workspace_id: Option<String>,
|
||||
|
||||
#[arg(long)]
|
||||
ops_json: String,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct SearchCommand {
|
||||
#[command(subcommand)]
|
||||
action: SearchAction,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum SearchAction {
|
||||
Documents(SearchDocumentsArgs),
|
||||
Blocks(SearchBlocksArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct SearchDocumentsArgs {
|
||||
#[arg(long)]
|
||||
query: String,
|
||||
|
||||
#[arg(long)]
|
||||
workspace_id: Option<String>,
|
||||
|
||||
#[arg(long, default_value_t = 20)]
|
||||
limit: u32,
|
||||
|
||||
#[arg(long)]
|
||||
cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct SearchBlocksArgs {
|
||||
#[arg(long)]
|
||||
query: String,
|
||||
|
||||
#[arg(long)]
|
||||
page_id: Option<String>,
|
||||
|
||||
#[arg(long, default_value_t = 20)]
|
||||
limit: u32,
|
||||
|
||||
#[arg(long)]
|
||||
cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct SidebarCommand {
|
||||
#[command(subcommand)]
|
||||
action: SidebarAction,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum SidebarAction {
|
||||
Dataset(SidebarDatasetArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct SidebarDatasetArgs {
|
||||
#[arg(long)]
|
||||
workspace_id: String,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct ToolCommand {
|
||||
#[command(subcommand)]
|
||||
action: ToolAction,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum ToolAction {
|
||||
Run(ToolRunArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
struct ToolRunArgs {
|
||||
#[arg(long)]
|
||||
tool_name: String,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = ToolKindArg::Command)]
|
||||
kind: ToolKindArg,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = ToolModeArg::Plan)]
|
||||
mode: ToolModeArg,
|
||||
|
||||
#[arg(long)]
|
||||
args_json: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
|
||||
enum ToolKindArg {
|
||||
Command,
|
||||
Query,
|
||||
Job,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]
|
||||
enum ToolModeArg {
|
||||
Plan,
|
||||
Result,
|
||||
ExplainPlan,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
let context = CliContext {
|
||||
actor_id: cli.global.actor_id,
|
||||
actor_type: cli.global.actor_type,
|
||||
session_id: cli.global.session_id,
|
||||
reason: cli.global.reason,
|
||||
idempotency_key: cli.global.idempotency_key,
|
||||
validate_only: cli.global.validate_only,
|
||||
dry_run: cli.global.dry_run,
|
||||
};
|
||||
|
||||
let result = match cli.command {
|
||||
Commands::Page(command) => match command.action {
|
||||
PageAction::Get(args) => {
|
||||
plan_page_get(&context, &args.page_id, args.workspace_id.as_deref())
|
||||
}
|
||||
PageAction::Title(args) => plan_page_title(
|
||||
&context,
|
||||
&args.page_id,
|
||||
args.workspace_id.as_deref(),
|
||||
&args.title,
|
||||
),
|
||||
PageAction::Save(args) => plan_page_save(
|
||||
&context,
|
||||
&args.page_id,
|
||||
args.workspace_id.as_deref(),
|
||||
args.revision,
|
||||
&args.content_json,
|
||||
args.conflict_detection_key.as_deref(),
|
||||
),
|
||||
},
|
||||
Commands::Block(command) => match command.action {
|
||||
BlockAction::Insert(args) => plan_block_insert(
|
||||
&context,
|
||||
&args.workspace_id,
|
||||
&args.page_id,
|
||||
&args.content,
|
||||
&args.block_type,
|
||||
args.parent_block_id.as_deref(),
|
||||
args.prev_block_id.as_deref(),
|
||||
),
|
||||
BlockAction::Patch(args) => plan_block_patch(
|
||||
&context,
|
||||
args.workspace_id.as_deref(),
|
||||
&args.page_id,
|
||||
&args.block_id,
|
||||
args.revision,
|
||||
&args.snapshot_json,
|
||||
args.conflict_detection_key.as_deref(),
|
||||
),
|
||||
},
|
||||
Commands::Mindmap(command) => match command.action {
|
||||
MindmapAction::Get(args) => plan_mindmap_get(
|
||||
&context,
|
||||
args.workspace_id.as_deref(),
|
||||
&args.document_id,
|
||||
&args.mindmap_id,
|
||||
),
|
||||
MindmapAction::Put(args) => plan_mindmap_put(
|
||||
&context,
|
||||
args.workspace_id.as_deref(),
|
||||
&args.document_id,
|
||||
&args.mindmap_id,
|
||||
&args.data_json,
|
||||
args.create_only,
|
||||
),
|
||||
MindmapAction::Op(args) => plan_mindmap_op(
|
||||
&context,
|
||||
args.workspace_id.as_deref(),
|
||||
&args.document_id,
|
||||
&args.mindmap_id,
|
||||
&args.ops_json,
|
||||
),
|
||||
},
|
||||
Commands::Search(command) => match command.action {
|
||||
SearchAction::Documents(args) => plan_search_documents(
|
||||
&context,
|
||||
&args.query,
|
||||
args.workspace_id.as_deref(),
|
||||
args.limit,
|
||||
args.cursor.as_deref(),
|
||||
),
|
||||
SearchAction::Blocks(args) => plan_search_blocks(
|
||||
&context,
|
||||
&args.query,
|
||||
args.page_id.as_deref(),
|
||||
args.limit,
|
||||
args.cursor.as_deref(),
|
||||
),
|
||||
},
|
||||
Commands::Sidebar(command) => match command.action {
|
||||
SidebarAction::Dataset(args) => plan_sidebar_dataset(&context, &args.workspace_id),
|
||||
},
|
||||
Commands::Tool(command) => match command.action {
|
||||
ToolAction::Run(args) => plan_tool_run(
|
||||
&context,
|
||||
&args.tool_name,
|
||||
to_invocation_kind(args.kind),
|
||||
to_execution_mode(args.mode),
|
||||
&args.args_json,
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(output) => emit_success(&output, cli.global.json),
|
||||
Err(error) => emit_error(&error, cli.global.json),
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_success(output: &CliJsonOutput, json_mode: bool) {
|
||||
if json_mode {
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(output).expect("CLI JSON 输出必须可序列化")
|
||||
);
|
||||
} else {
|
||||
println!("{}", render_plain_output(output));
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_error(error: &CliError, json_mode: bool) -> ! {
|
||||
if json_mode {
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&serde_json::json!({
|
||||
"ok": false,
|
||||
"entrypoint": "mnote-cli",
|
||||
"error": {
|
||||
"code": error.code,
|
||||
"message": error.message,
|
||||
}
|
||||
}))
|
||||
.expect("CLI 错误 JSON 输出必须可序列化")
|
||||
);
|
||||
} else {
|
||||
eprintln!("{}: {}", error.code, error.message);
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
fn to_invocation_kind(kind: ToolKindArg) -> InvocationKind {
|
||||
match kind {
|
||||
ToolKindArg::Command => InvocationKind::Command,
|
||||
ToolKindArg::Query => InvocationKind::Query,
|
||||
ToolKindArg::Job => InvocationKind::Job,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_execution_mode(mode: ToolModeArg) -> ToolExecutionMode {
|
||||
match mode {
|
||||
ToolModeArg::Plan => ToolExecutionMode::Plan,
|
||||
ToolModeArg::Result => ToolExecutionMode::Result,
|
||||
ToolModeArg::ExplainPlan => ToolExecutionMode::ExplainPlan,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user