Skip to content

Commit 11e8a7b

Browse files
jamesaphoenixclaude
andcommitted
release: v0.5.5 — comments tab, icon tabs, AI settings fixes, resize perf
- Move comments from bottom strip to dedicated right-panel tab with grouped-by-file view, inline edit, and click-to-scroll-to-line - Replace text tab labels (Activity/Annotations/Source) with SVG icons (pulse, speech bubble, document, code brackets) with tooltips - Tab order: LLM → Comments → Info → Subsystem Source - Fix right panel resize jank with requestAnimationFrame throttling and disable CSS transitions during drag - Add comment edit/update: pencil button + double-click inline editing with new update_comment_cached Rust backend command - Comment badge click now scrolls diff viewer to first comment line - Fix sidebar tab text squashing when panel is narrow (CSS truncation) - AI settings: annotations_enabled + refinement_enabled now default true, annotations_enabled persisted to config, changing primary backend syncs refinement provider/model - 33 new tests across config, commands, and comment CRUD Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 104ee71 commit 11e8a7b

9 files changed

Lines changed: 1249 additions & 34 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ members = ["crates/diffcore-core", "crates/diffcore-cli", "crates/diffcore-tauri
33
resolver = "2"
44

55
[workspace.package]
6-
version = "0.5.4"
6+
version = "0.5.5"
77
edition = "2021"
88
license = "MIT"
99

crates/diffcore-cli/src/main.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1371,8 +1371,9 @@ mod tests {
13711371
#[test]
13721372
fn test_refine_flag_overrides_config() {
13731373
let mut config = DiffcoreConfig::default();
1374-
assert!(!config.llm.refinement.enabled);
1374+
assert!(config.llm.refinement.enabled);
13751375

1376+
// Even when starting from enabled, explicit flag should still work
13761377
let refine = true;
13771378
let refine_model: Option<String> = Some("gpt-4.1".to_string());
13781379

@@ -1391,6 +1392,8 @@ mod tests {
13911392
#[test]
13921393
fn test_refine_model_without_refine_enables_refinement() {
13931394
let mut config = DiffcoreConfig::default();
1395+
// Disable first to test that --refine-model alone re-enables
1396+
config.llm.refinement.enabled = false;
13941397
assert!(!config.llm.refinement.enabled);
13951398

13961399
let refine_model: Option<String> = Some("claude-sonnet-4-6".to_string());
@@ -1414,6 +1417,7 @@ mod tests {
14141417
model: Some("claude-sonnet-4-6".to_string()),
14151418
key_cmd: Some("echo main-key".to_string()),
14161419
key: Some("main-inline-key".to_string()),
1420+
annotations_enabled: true,
14171421
refinement: diffcore_core::config::RefinementConfig {
14181422
enabled: true,
14191423
provider: Some("openai".to_string()),
@@ -1468,6 +1472,7 @@ mod tests {
14681472
model: Some("claude-sonnet-4-6".to_string()),
14691473
key_cmd: Some("echo main-key".to_string()),
14701474
key: Some("main-inline-key".to_string()),
1475+
annotations_enabled: true,
14711476
refinement: diffcore_core::config::RefinementConfig {
14721477
enabled: true,
14731478
provider: None,

crates/diffcore-core/src/config.rs

Lines changed: 177 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ fn default_include_uncommitted() -> bool {
108108
true
109109
}
110110

111+
fn default_true() -> bool {
112+
true
113+
}
114+
111115
impl Default for DiffConfig {
112116
fn default() -> Self {
113117
Self {
@@ -132,6 +136,9 @@ pub struct LlmConfig {
132136
/// Precedence: key_cmd > key > env vars.
133137
#[serde(default, skip_serializing_if = "Option::is_none")]
134138
pub key: Option<String>,
139+
/// Whether LLM annotations are enabled (default: true).
140+
#[serde(default = "default_true")]
141+
pub annotations_enabled: bool,
135142
/// Optional LLM refinement pass configuration.
136143
#[serde(default)]
137144
pub refinement: RefinementConfig,
@@ -145,8 +152,8 @@ pub struct LlmConfig {
145152
/// refine again if score improved, up to `max_iterations`.
146153
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
147154
pub struct RefinementConfig {
148-
/// Whether refinement is enabled (default: false).
149-
#[serde(default)]
155+
/// Whether refinement is enabled (default: true).
156+
#[serde(default = "default_true")]
150157
pub enabled: bool,
151158
/// Provider for refinement (can differ from annotation provider).
152159
#[serde(default)]
@@ -170,7 +177,7 @@ fn default_max_iterations() -> u32 {
170177
impl Default for RefinementConfig {
171178
fn default() -> Self {
172179
Self {
173-
enabled: false,
180+
enabled: true,
174181
provider: None,
175182
model: None,
176183
key_cmd: None,
@@ -186,6 +193,7 @@ impl Default for LlmConfig {
186193
model: None,
187194
key_cmd: None,
188195
key: None,
196+
annotations_enabled: true,
189197
refinement: RefinementConfig::default(),
190198
}
191199
}
@@ -954,7 +962,7 @@ events = ["src/handlers/events/**/*.ts"]
954962
#[test]
955963
fn test_refinement_config_defaults() {
956964
let config = DiffcoreConfig::default();
957-
assert!(!config.llm.refinement.enabled);
965+
assert!(config.llm.refinement.enabled);
958966
assert_eq!(config.llm.refinement.provider, None);
959967
assert_eq!(config.llm.refinement.model, None);
960968
assert_eq!(config.llm.refinement.key_cmd, None);
@@ -981,13 +989,13 @@ max_iterations = 3
981989
}
982990

983991
#[test]
984-
fn test_refinement_disabled_by_default() {
992+
fn test_refinement_enabled_by_default() {
985993
let toml_str = r#"
986994
[llm]
987995
provider = "anthropic"
988996
"#;
989997
let config = DiffcoreConfig::from_str(toml_str).unwrap();
990-
assert!(!config.llm.refinement.enabled);
998+
assert!(config.llm.refinement.enabled);
991999
assert_eq!(config.llm.refinement.max_iterations, 1);
9921000
}
9931001

@@ -1149,4 +1157,167 @@ domain = "src/services/**"
11491157
}
11501158
}
11511159
}
1160+
1161+
// ── Annotations Enabled Tests ──
1162+
1163+
#[test]
1164+
fn test_annotations_enabled_defaults_true() {
1165+
let config = DiffcoreConfig::default();
1166+
assert!(config.llm.annotations_enabled);
1167+
}
1168+
1169+
#[test]
1170+
fn test_annotations_enabled_serde_default_true() {
1171+
// When annotations_enabled is missing from TOML, it should default to true
1172+
let toml_str = r#"
1173+
[llm]
1174+
provider = "anthropic"
1175+
"#;
1176+
let config = DiffcoreConfig::from_str(toml_str).unwrap();
1177+
assert!(config.llm.annotations_enabled);
1178+
}
1179+
1180+
#[test]
1181+
fn test_annotations_enabled_explicit_false() {
1182+
let toml_str = r#"
1183+
[llm]
1184+
provider = "anthropic"
1185+
annotations_enabled = false
1186+
"#;
1187+
let config = DiffcoreConfig::from_str(toml_str).unwrap();
1188+
assert!(!config.llm.annotations_enabled);
1189+
}
1190+
1191+
#[test]
1192+
fn test_annotations_enabled_explicit_true() {
1193+
let toml_str = r#"
1194+
[llm]
1195+
provider = "anthropic"
1196+
annotations_enabled = true
1197+
"#;
1198+
let config = DiffcoreConfig::from_str(toml_str).unwrap();
1199+
assert!(config.llm.annotations_enabled);
1200+
}
1201+
1202+
#[test]
1203+
fn test_annotations_enabled_roundtrip() {
1204+
let mut config = DiffcoreConfig::default();
1205+
config.llm.annotations_enabled = false;
1206+
1207+
let toml_str = toml::to_string_pretty(&config).unwrap();
1208+
let back = DiffcoreConfig::from_str(&toml_str).unwrap();
1209+
assert!(!back.llm.annotations_enabled);
1210+
}
1211+
1212+
#[test]
1213+
fn test_annotations_enabled_json_roundtrip() {
1214+
let config = LlmConfig {
1215+
annotations_enabled: false,
1216+
..Default::default()
1217+
};
1218+
let json = serde_json::to_string(&config).unwrap();
1219+
let back: LlmConfig = serde_json::from_str(&json).unwrap();
1220+
assert!(!back.annotations_enabled);
1221+
}
1222+
1223+
#[test]
1224+
fn test_refinement_enabled_defaults_true_in_llm_config() {
1225+
let config = LlmConfig::default();
1226+
assert!(config.refinement.enabled);
1227+
}
1228+
1229+
#[test]
1230+
fn test_refinement_enabled_explicit_false_overrides_default() {
1231+
let toml_str = r#"
1232+
[llm.refinement]
1233+
enabled = false
1234+
"#;
1235+
let config = DiffcoreConfig::from_str(toml_str).unwrap();
1236+
assert!(!config.llm.refinement.enabled);
1237+
}
1238+
1239+
#[test]
1240+
fn test_both_defaults_true_on_empty_config() {
1241+
let config = DiffcoreConfig::default();
1242+
assert!(config.llm.annotations_enabled, "annotations should default to true");
1243+
assert!(config.llm.refinement.enabled, "refinement should default to true");
1244+
}
1245+
1246+
#[test]
1247+
fn test_both_defaults_true_on_minimal_toml() {
1248+
let toml_str = "";
1249+
let config = DiffcoreConfig::from_str(toml_str).unwrap();
1250+
assert!(config.llm.annotations_enabled, "annotations should default to true");
1251+
assert!(config.llm.refinement.enabled, "refinement should default to true");
1252+
}
1253+
1254+
#[test]
1255+
fn test_annotations_and_refinement_independent() {
1256+
// Can enable one and disable the other
1257+
let toml_str = r#"
1258+
[llm]
1259+
annotations_enabled = false
1260+
1261+
[llm.refinement]
1262+
enabled = true
1263+
"#;
1264+
let config = DiffcoreConfig::from_str(toml_str).unwrap();
1265+
assert!(!config.llm.annotations_enabled);
1266+
assert!(config.llm.refinement.enabled);
1267+
1268+
let toml_str2 = r#"
1269+
[llm]
1270+
annotations_enabled = true
1271+
1272+
[llm.refinement]
1273+
enabled = false
1274+
"#;
1275+
let config2 = DiffcoreConfig::from_str(toml_str2).unwrap();
1276+
assert!(config2.llm.annotations_enabled);
1277+
assert!(!config2.llm.refinement.enabled);
1278+
}
1279+
1280+
#[test]
1281+
fn test_global_defaults_merge_with_annotations() {
1282+
// Test that global config merge still works with annotations_enabled
1283+
let mut local = DiffcoreConfig::from_str(r#"
1284+
[llm]
1285+
annotations_enabled = false
1286+
"#).unwrap();
1287+
let global = DiffcoreConfig::from_str(r#"
1288+
[llm]
1289+
provider = "anthropic"
1290+
1291+
[llm.refinement]
1292+
enabled = true
1293+
provider = "openai"
1294+
"#).unwrap();
1295+
1296+
local.apply_global_llm_defaults(&global);
1297+
1298+
// Local explicit false should be preserved
1299+
assert!(!local.llm.annotations_enabled);
1300+
// Global provider should fill in missing local
1301+
assert_eq!(local.llm.provider, Some("anthropic".to_string()));
1302+
// Refinement from either local (default true) or global should be true
1303+
assert!(local.llm.refinement.enabled);
1304+
}
1305+
1306+
#[test]
1307+
fn test_save_global_roundtrip_annotations_enabled() {
1308+
// Test that annotations_enabled survives save_global / load_global cycle
1309+
let dir = tempfile::tempdir().unwrap();
1310+
std::env::set_var("DIFFCORE_GLOBAL_CONFIG_DIR", dir.path().to_str().unwrap());
1311+
1312+
let mut config = DiffcoreConfig::default();
1313+
config.llm.annotations_enabled = false;
1314+
config.llm.refinement.enabled = false;
1315+
config.save_global().unwrap();
1316+
1317+
let loaded = DiffcoreConfig::load_global().unwrap();
1318+
assert!(!loaded.llm.annotations_enabled, "annotations_enabled should survive save/load");
1319+
assert!(!loaded.llm.refinement.enabled, "refinement.enabled should survive save/load");
1320+
1321+
std::env::remove_var("DIFFCORE_GLOBAL_CONFIG_DIR");
1322+
}
11521323
}

0 commit comments

Comments
 (0)