1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use std::str::FromStr;
/// Selects a bounded operation catalog independently of any transport.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum ToolProfile {
/// Code intelligence plus semantic, SEO, and memory extensions.
#[default]
All,
/// Repository and coding-agent intelligence without SEO-specific tools.
Code,
/// Content-graph, search, semantic, and SEO analysis.
Seo,
/// Exported n8n workflows without the full repository catalog.
N8n,
/// Exported Dify YAML apps without the full repository catalog.
Dify,
/// Agent Plugins, Skills, and native MCP configuration files.
Agent,
/// Mermaid flowchart diagrams and explicit diagram bindings.
Diagram,
}
impl ToolProfile {
#[must_use]
pub fn allows(self, tool: &str) -> bool {
match self {
Self::All => true,
Self::Code => tool != "seo_link_suggestions",
Self::N8n => matches!(
tool,
"n8n_inventory"
| "n8n_trace"
| "n8n_context"
| "graph_stats"
| "get_node"
| "get_neighbors"
| "query_graph"
| "search_code"
| "read_source"
| "inspect_symbol"
| "context_bundle"
| "rebuild_graph"
| "open_repo"
| "list_known_repos"
),
Self::Dify => matches!(
tool,
"dify_inventory"
| "dify_trace"
| "dify_context"
| "graph_stats"
| "get_node"
| "get_neighbors"
| "query_graph"
| "search_code"
| "read_source"
| "inspect_symbol"
| "context_bundle"
| "rebuild_graph"
| "open_repo"
| "list_known_repos"
),
Self::Agent => matches!(
tool,
"agent_inventory"
| "agent_trace"
| "agent_context"
| "agent_change_impact"
| "graph_stats"
| "get_node"
| "get_neighbors"
| "query_graph"
| "search_code"
| "read_source"
| "inspect_symbol"
| "context_bundle"
| "rebuild_graph"
| "open_repo"
| "list_known_repos"
),
Self::Diagram => matches!(
tool,
"diagram_inventory"
| "diagram_trace"
| "diagram_context"
| "change_impact"
| "graph_stats"
| "get_node"
| "get_neighbors"
| "query_graph"
| "search_code"
| "read_source"
| "inspect_symbol"
| "context_bundle"
| "rebuild_graph"
| "open_repo"
| "list_known_repos"
),
Self::Seo => matches!(
tool,
"graph_stats"
| "get_node"
| "get_neighbors"
| "query_graph"
| "shortest_path"
| "search_code"
| "read_source"
| "context_bundle"
| "list_communities"
| "get_community"
| "module_map"
| "rebuild_graph"
| "open_repo"
| "list_known_repos"
| "semantic_link"
| "vector_search"
| "seo_link_suggestions"
| "memory_context"
),
}
}
}
impl FromStr for ToolProfile {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"all" => Ok(Self::All),
"code" => Ok(Self::Code),
"seo" | "content" => Ok(Self::Seo),
"n8n" => Ok(Self::N8n),
"dify" => Ok(Self::Dify),
"agent" => Ok(Self::Agent),
"diagram" | "mermaid" => Ok(Self::Diagram),
_ => Err(format!(
"unknown tool profile {value:?}; expected all, code, seo, n8n, dify, agent, or diagram"
)),
}
}
}