Update: 将子项目从 submodule 转为完整内容

- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用
- 添加所有子项目的完整源代码
- 保留原始 .git 为 .git.bak 备份
This commit is contained in:
freedak
2026-07-04 19:20:46 +08:00
parent 54d6465fa7
commit f7a720204a
3360 changed files with 802660 additions and 3 deletions
@@ -0,0 +1,44 @@
use nomi_protocol::commands::ApprovalScope;
use nomi_protocol::events::ToolCategory;
use nomi_protocol::{ToolApprovalManager, ToolApprovalResult};
use rstest::rstest;
#[rstest]
#[case(ApprovalScope::Once, ToolCategory::Exec, "exec", false)]
#[case(ApprovalScope::Always, ToolCategory::Edit, "edit", true)]
#[tokio::test]
async fn approve_resolves_request_and_updates_auto_approval(
#[case] scope: ApprovalScope,
#[case] category: ToolCategory,
#[case] category_name: &str,
#[case] should_auto_approve: bool,
) {
let manager = ToolApprovalManager::new();
let rx = manager.request_approval("call-1", &category);
manager.approve("call-1", scope);
let result = rx.await.expect("approval result should arrive");
assert!(matches!(result, ToolApprovalResult::Approved));
assert_eq!(manager.is_auto_approved(category_name), should_auto_approve);
}
#[tokio::test]
async fn resolve_preserves_denial_reason() {
let manager = ToolApprovalManager::new();
let rx = manager.request_approval("call-2", &ToolCategory::Exec);
manager.resolve(
"call-2",
ToolApprovalResult::Denied {
reason: "policy violation".to_string(),
},
);
let result = rx.await.expect("denial result should arrive");
assert!(matches!(
result,
ToolApprovalResult::Denied { reason } if reason == "policy violation"
));
assert!(!manager.is_auto_approved("exec"));
}
@@ -0,0 +1,84 @@
use nomi_protocol::events::{Capabilities, ProtocolEvent};
#[test]
fn capabilities_serialize_with_all_fields() {
let caps = Capabilities {
tool_approval: true,
thinking: true,
effort: false,
effort_levels: vec![],
modes: vec!["default".into(), "auto_edit".into(), "yolo".into()],
current_mode: "default".into(),
mcp: true,
};
let event = ProtocolEvent::Ready {
version: "0.2.0".into(),
session_id: None,
capabilities: caps,
};
let json = serde_json::to_string(&event).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["type"], "ready");
assert_eq!(parsed["capabilities"]["thinking"], true);
assert_eq!(parsed["capabilities"]["effort"], false);
assert!(
parsed["capabilities"]["effort_levels"]
.as_array()
.unwrap()
.is_empty()
);
assert_eq!(parsed["capabilities"]["modes"].as_array().unwrap().len(), 3);
assert_eq!(parsed["capabilities"]["current_mode"], "default");
}
#[test]
fn config_changed_event_serializes_correctly() {
let caps = Capabilities {
tool_approval: true,
thinking: false,
effort: true,
effort_levels: vec!["low".into(), "medium".into(), "high".into()],
modes: vec!["default".into(), "auto_edit".into(), "yolo".into()],
current_mode: "default".into(),
mcp: false,
};
let event = ProtocolEvent::ConfigChanged { capabilities: caps };
let json = serde_json::to_string(&event).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["type"], "config_changed");
assert_eq!(parsed["capabilities"]["effort_levels"][1], "medium");
}
#[test]
fn capabilities_with_effort_levels_roundtrip() {
let caps = Capabilities {
tool_approval: true,
thinking: false,
effort: true,
effort_levels: vec!["low".into(), "medium".into(), "high".into()],
modes: vec!["default".into(), "auto_edit".into(), "yolo".into()],
current_mode: "default".into(),
mcp: true,
};
let event = ProtocolEvent::Ready {
version: "0.2.0".into(),
session_id: Some("test-session".into()),
capabilities: caps,
};
let json = serde_json::to_string(&event).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["capabilities"]["effort"], true);
assert_eq!(
parsed["capabilities"]["effort_levels"]
.as_array()
.unwrap()
.len(),
3
);
assert_eq!(parsed["capabilities"]["effort_levels"][0], "low");
assert_eq!(parsed["capabilities"]["effort_levels"][2], "high");
assert_eq!(parsed["session_id"], "test-session");
}
@@ -0,0 +1,85 @@
use nomi_protocol::commands::{ApprovalScope, ProtocolCommand, SessionMode};
use rstest::rstest;
#[rstest]
#[case(
r#"{"type":"message","msg_id":"m1","content":"Hello"}"#,
ProtocolCommand::Message {
msg_id: "m1".to_string(),
content: "Hello".to_string(),
files: vec![],
}
)]
#[case(
r#"{"type":"message","msg_id":"m2","content":"Read this","files":["/tmp/a.rs"]}"#,
ProtocolCommand::Message {
msg_id: "m2".to_string(),
content: "Read this".to_string(),
files: vec!["/tmp/a.rs".to_string()],
}
)]
#[case(r#"{"type":"stop"}"#, ProtocolCommand::Stop)]
#[case(
r#"{"type":"init_history","text":"history"}"#,
ProtocolCommand::InitHistory {
text: "history".to_string(),
}
)]
#[case(
r#"{"type":"set_mode","mode":"default"}"#,
ProtocolCommand::SetMode {
mode: SessionMode::Default,
}
)]
#[case(
r#"{"type":"set_mode","mode":"auto_edit"}"#,
ProtocolCommand::SetMode {
mode: SessionMode::AutoEdit,
}
)]
#[case(
r#"{"type":"set_mode","mode":"yolo"}"#,
ProtocolCommand::SetMode {
mode: SessionMode::Yolo,
}
)]
fn deserializes_protocol_commands(#[case] json: &str, #[case] expected: ProtocolCommand) {
let cmd: ProtocolCommand = serde_json::from_str(json).expect("command should deserialize");
assert_eq!(cmd, expected);
}
#[rstest]
#[case(r#"{"type":"tool_approve","call_id":"c1"}"#, ApprovalScope::Once)]
#[case(
r#"{"type":"tool_approve","call_id":"c1","scope":"always"}"#,
ApprovalScope::Always
)]
fn deserializes_tool_approve_scope(#[case] json: &str, #[case] expected_scope: ApprovalScope) {
let cmd: ProtocolCommand = serde_json::from_str(json).expect("tool approve should deserialize");
match cmd {
ProtocolCommand::ToolApprove { call_id, scope } => {
assert_eq!(call_id, "c1");
assert_eq!(scope, expected_scope);
}
other => panic!("expected ToolApprove, got {other:?}"),
}
}
#[rstest]
#[case(r#"{"type":"tool_deny","call_id":"c1"}"#, "")]
#[case(
r#"{"type":"tool_deny","call_id":"c1","reason":"not allowed"}"#,
"not allowed"
)]
fn deserializes_tool_deny_reason(#[case] json: &str, #[case] expected_reason: &str) {
let cmd: ProtocolCommand = serde_json::from_str(json).expect("tool deny should deserialize");
match cmd {
ProtocolCommand::ToolDeny { call_id, reason } => {
assert_eq!(call_id, "c1");
assert_eq!(reason, expected_reason);
}
other => panic!("expected ToolDeny, got {other:?}"),
}
}
@@ -0,0 +1,186 @@
use nomi_protocol::commands::ProtocolCommand;
#[test]
fn parse_set_config_with_model() {
let json = r#"{"type":"set_config","model":"claude-sonnet-4-5-20250514"}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig { model, .. } => {
assert_eq!(model.as_deref(), Some("claude-sonnet-4-5-20250514"));
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
#[test]
fn parse_set_config_empty() {
let json = r#"{"type":"set_config"}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig { model, .. } => {
assert!(model.is_none());
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
#[test]
fn parse_set_config_null_model() {
let json = r#"{"type":"set_config","model":null}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig { model, .. } => {
assert!(model.is_none());
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
#[test]
fn parse_set_config_unknown_fields_ignored() {
let json = r#"{"type":"set_config","model":"x","future_field":true,"nested":{"a":1}}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig { model, .. } => {
assert_eq!(model.as_deref(), Some("x"));
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
#[test]
fn existing_commands_still_parse() {
// AC-7: Verify SetConfig addition doesn't break existing variants
let message = r#"{"type":"message","msg_id":"m1","content":"hello"}"#;
assert!(serde_json::from_str::<ProtocolCommand>(message).is_ok());
let stop = r#"{"type":"stop"}"#;
assert!(serde_json::from_str::<ProtocolCommand>(stop).is_ok());
let approve = r#"{"type":"tool_approve","call_id":"c1"}"#;
assert!(serde_json::from_str::<ProtocolCommand>(approve).is_ok());
let deny = r#"{"type":"tool_deny","call_id":"c1"}"#;
assert!(serde_json::from_str::<ProtocolCommand>(deny).is_ok());
let init = r#"{"type":"init_history","text":"ctx"}"#;
assert!(serde_json::from_str::<ProtocolCommand>(init).is_ok());
let mode = r#"{"type":"set_mode","mode":"yolo"}"#;
assert!(serde_json::from_str::<ProtocolCommand>(mode).is_ok());
}
// --- Cycle 2: Effort parsing tests ---
#[test]
fn parse_set_config_with_effort() {
let json = r#"{"type":"set_config","effort":"high"}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig { effort, model, .. } => {
assert_eq!(effort.as_deref(), Some("high"));
assert!(model.is_none());
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
#[test]
fn parse_set_config_with_null_effort() {
let json = r#"{"type":"set_config","effort":null}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig { effort, .. } => {
assert!(effort.is_none());
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
// --- Cycle 2: Thinking parsing tests ---
#[test]
fn parse_set_config_with_thinking_enabled_and_budget() {
let json = r#"{"type":"set_config","thinking":"enabled","thinking_budget":16000}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig {
thinking,
thinking_budget,
..
} => {
assert_eq!(thinking.as_deref(), Some("enabled"));
assert_eq!(thinking_budget, Some(16000));
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
#[test]
fn parse_set_config_with_thinking_disabled() {
let json = r#"{"type":"set_config","thinking":"disabled"}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig {
thinking,
thinking_budget,
..
} => {
assert_eq!(thinking.as_deref(), Some("disabled"));
assert!(thinking_budget.is_none());
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
#[test]
fn parse_set_config_with_null_thinking() {
let json = r#"{"type":"set_config","thinking":null}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig { thinking, .. } => {
assert!(thinking.is_none());
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
#[test]
fn parse_set_config_thinking_enabled_no_budget() {
let json = r#"{"type":"set_config","thinking":"enabled"}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig {
thinking,
thinking_budget,
..
} => {
assert_eq!(thinking.as_deref(), Some("enabled"));
assert!(thinking_budget.is_none());
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}
// --- Cycle 2: Combined fields test ---
#[test]
fn parse_set_config_all_fields() {
let json = r#"{"type":"set_config","model":"m","effort":"low","thinking":"disabled"}"#;
let cmd: ProtocolCommand = serde_json::from_str(json).unwrap();
match cmd {
ProtocolCommand::SetConfig {
model,
effort,
thinking,
thinking_budget,
..
} => {
assert_eq!(model.as_deref(), Some("m"));
assert_eq!(effort.as_deref(), Some("low"));
assert_eq!(thinking.as_deref(), Some("disabled"));
assert!(thinking_budget.is_none());
}
other => panic!("expected SetConfig, got: {other:?}"),
}
}