use crate::schema::{Kind, Node};
pub(super) fn query_intent_matches(
node: &Node,
aliases: &[String],
terms: &[String],
) -> Vec<&'static str> {
let mut out = Vec::new();
if query_has_agent_intent(terms) && node_matches_agent(node, aliases) {
out.push("agent");
}
if query_has_tool_intent(terms) && node_matches_tool(node, aliases) {
out.push("tool");
}
if query_has_command_intent(terms) && node_matches_command(aliases) {
out.push("command");
}
if query_has_workflow_intent(terms) && node_matches_workflow(node, aliases) {
out.push("workflow");
}
if query_has_artifact_intent(terms) && node_matches_artifact(aliases) {
out.push("artifact");
}
if query_has_contract_intent(terms) && node_matches_contract(node, aliases) {
out.push("contract");
}
if query_has_code_intent(terms) && node_matches_code(node, aliases) {
out.push("code");
}
if query_has_doc_intent(terms) && node_matches_doc(node, aliases) {
out.push("doc");
}
out
}
fn has_any_term(terms: &[String], words: &[&str]) -> bool {
terms
.iter()
.any(|term| words.iter().any(|word| term == word))
}
fn has_alias(aliases: &[String], words: &[&str]) -> bool {
aliases
.iter()
.any(|alias| words.iter().any(|word| alias == word))
}
fn query_has_agent_intent(terms: &[String]) -> bool {
has_any_term(
terms,
&[
"agent",
"assistant",
"expert",
"maintainer",
"operator",
"owner",
"persona",
"reviewer",
"role",
"specialist",
"worker",
],
)
}
fn query_has_tool_intent(terms: &[String]) -> bool {
has_any_term(
terms,
&[
"action",
"capability",
"endpoint",
"extension",
"integration",
"plugin",
"tool",
"utility",
],
)
}
fn query_has_command_intent(terms: &[String]) -> bool {
has_any_term(
terms,
&[
"cli",
"command",
"execute",
"execution",
"invocation",
"run",
"slash",
"subcommand",
],
)
}
fn query_has_workflow_intent(terms: &[String]) -> bool {
has_any_term(
terms,
&[
"flow",
"lifecycle",
"phase",
"pipeline",
"playbook",
"procedure",
"proces",
"process",
"route",
"sequence",
"workflow",
],
)
}
fn query_has_artifact_intent(terms: &[String]) -> bool {
has_any_term(
terms,
&[
"artifact",
"document",
"file",
"generated",
"log",
"manifest",
"output",
"report",
"result",
"snapshot",
],
) || (terms.iter().any(|term| term == "graph")
&& has_any_term(
terms,
&[
"artifact",
"file",
"generated",
"log",
"manifest",
"output",
"path",
"report",
"snapshot",
],
))
}
fn query_has_contract_intent(terms: &[String]) -> bool {
has_any_term(
terms,
&[
"constraint",
"contract",
"guardrail",
"invariant",
"policy",
"requirement",
"rule",
"schema",
],
)
}
fn query_has_code_intent(terms: &[String]) -> bool {
has_any_term(
terms,
&[
"class",
"code",
"component",
"definition",
"fileline",
"function",
"hook",
"implement",
"implementation",
"implemented",
"method",
"module",
"route",
"source",
"struct",
],
)
}
fn query_has_doc_intent(terms: &[String]) -> bool {
has_any_term(
terms,
&[
"concept",
"doc",
"docs",
"documentation",
"explanation",
"guide",
"note",
"readme",
"reference",
"wiki",
],
)
}
fn node_matches_agent(node: &Node, aliases: &[String]) -> bool {
node.kind == Kind::Agent
|| has_alias(
aliases,
&[
"agent",
"assistant",
"expert",
"maintainer",
"operator",
"owner",
"persona",
"reviewer",
"role",
"specialist",
"worker",
],
)
}
fn node_matches_tool(node: &Node, aliases: &[String]) -> bool {
node.subkind.as_deref() == Some("mcp")
|| has_alias(
aliases,
&[
"action",
"capability",
"endpoint",
"extension",
"integration",
"plugin",
"tool",
"utility",
],
)
}
fn node_matches_command(aliases: &[String]) -> bool {
has_alias(
aliases,
&[
"cli",
"command",
"invocation",
"slash",
"slash command",
"subcommand",
],
)
}
fn node_matches_workflow(node: &Node, aliases: &[String]) -> bool {
node.subkind.as_deref() == Some("workflow")
|| node.subkind.as_deref() == Some("archetype")
|| has_alias(
aliases,
&[
"archetype",
"flow",
"lifecycle",
"phase",
"pipeline",
"playbook",
"procedure",
"process",
"route",
"sequence",
"workflow",
],
)
}
fn node_matches_artifact(aliases: &[String]) -> bool {
has_alias(
aliases,
&[
"artifact",
"document",
"file",
"generated",
"graph file",
"log",
"manifest",
"output",
"report",
"result",
"snapshot",
],
)
}
fn node_matches_contract(node: &Node, aliases: &[String]) -> bool {
node.subkind.as_deref() == Some("contract")
|| has_alias(
aliases,
&[
"constraint",
"contract",
"guardrail",
"invariant",
"policy",
"requirement",
"rule",
"schema",
],
)
}
fn node_matches_code(node: &Node, aliases: &[String]) -> bool {
matches!(
node.kind,
Kind::Function | Kind::Type | Kind::Trait | Kind::Module
) || node.span.is_some()
|| has_alias(
aliases,
&[
"class",
"code",
"component",
"function",
"hook",
"interface",
"method",
"module",
"route",
"source",
"struct",
"type",
],
)
}
fn node_matches_doc(node: &Node, aliases: &[String]) -> bool {
matches!(node.kind, Kind::Doc | Kind::Skill)
|| has_alias(
aliases,
&[
"concept",
"doc",
"docs",
"documentation",
"guide",
"note",
"readme",
"reference",
"wiki",
],
)
}