settings.rs

 1use std::ops::Range;
 2
 3use tree_sitter::{Query, QueryMatch};
 4
 5use crate::MigrationPatterns;
 6
 7pub const SETTINGS_PATTERNS: MigrationPatterns = &[(
 8    SETTINGS_AGENT_SERVERS_CUSTOM_PATTERN,
 9    migrate_custom_agent_settings,
10)];
11
12const SETTINGS_AGENT_SERVERS_CUSTOM_PATTERN: &str = r#"(document
13    (object
14        (pair
15            key: (string (string_content) @agent-servers)
16            value: (object
17                (pair
18                    key: (string (string_content) @server-name)
19                    value: (object) @server-settings
20                )
21            )
22        )
23    )
24    (#eq? @agent-servers "agent_servers")
25)"#;
26
27fn migrate_custom_agent_settings(
28    contents: &str,
29    mat: &QueryMatch,
30    query: &Query,
31) -> Option<(Range<usize>, String)> {
32    let server_name_index = query.capture_index_for_name("server-name")?;
33    let server_name = mat.nodes_for_capture_index(server_name_index).next()?;
34    let server_name_text = &contents[server_name.byte_range()];
35
36    if matches!(server_name_text, "gemini" | "claude" | "codex") {
37        return None;
38    }
39
40    let server_settings_index = query.capture_index_for_name("server-settings")?;
41    let server_settings = mat.nodes_for_capture_index(server_settings_index).next()?;
42
43    let mut column = None;
44
45    // Parse the server settings to check what keys it contains
46    let mut cursor = server_settings.walk();
47    for child in server_settings.children(&mut cursor) {
48        if child.kind() == "pair" {
49            if let Some(key_node) = child.child_by_field_name("key") {
50                if let (None, Some(quote_content)) = (column, key_node.child(0)) {
51                    column = Some(quote_content.start_position().column);
52                }
53                if let Some(string_content) = key_node.child(1) {
54                    let key = &contents[string_content.byte_range()];
55                    match key {
56                        // If it already has a type key, don't modify it
57                        "type" => return None,
58                        _ => {}
59                    }
60                }
61            }
62        }
63    }
64
65    // Insert the type key at the beginning of the object
66    let start = server_settings.start_byte() + 1;
67    let indent = " ".repeat(column.unwrap_or(12));
68
69    Some((
70        start..start,
71        format!(
72            r#"
73{indent}"type": "custom","#
74        ),
75    ))
76}