pub const LOOPFLOW_DOC: &str = include_str!("builtins/LOOPFLOW.md");
pub const SURFACE_HEADLESS: &str = include_str!("builtins/surfaces/headless.md");
pub fn get_builtin_step(name: &str) -> Option<&'static str> {
BUILTIN_STEPS.get(name).copied()
}
pub fn builtin_step_description(name: &str) -> String {
let Some(content) = get_builtin_step(name) else {
return String::new();
};
step_description_from_content(content)
}
pub fn builtin_flow_description(name: &str) -> String {
let Some(content) = get_builtin_flow(name) else {
return String::new();
};
flow_description_from_content(content)
}
fn step_description_from_content(content: &str) -> String {
if let Some(desc) = frontmatter_description(content) {
return first_line(&desc);
}
let body = strip_frontmatter(content);
first_prose_line(body)
}
fn frontmatter_description(content: &str) -> Option<String> {
let stripped = content.strip_prefix("---")?;
let end = stripped.find("\n---")?;
let frontmatter = &stripped[..end];
let value: serde_yaml_ng::Value = serde_yaml_ng::from_str(frontmatter).ok()?;
let desc = value
.as_mapping()?
.get(serde_yaml_ng::Value::String("description".to_string()))?;
Some(desc.as_str()?.trim().to_string())
}
fn flow_description_from_content(content: &str) -> String {
for raw in content.lines() {
let trimmed = raw.trim_start();
if trimmed.starts_with("# ") {
return trimmed.trim_start_matches('#').trim().to_string();
}
if !trimmed.is_empty() {
break;
}
}
String::new()
}
fn strip_frontmatter(content: &str) -> &str {
let Some(stripped) = content.strip_prefix("---") else {
return content;
};
let Some(end) = stripped.find("\n---") else {
return content;
};
stripped[end + 4..].trim_start_matches('\n')
}
fn first_prose_line(body: &str) -> String {
for raw in body.lines() {
let line = raw.trim();
if line.is_empty() {
continue;
}
if line.starts_with('#') || line.starts_with("```") {
continue;
}
return line.to_string();
}
String::new()
}
fn first_line(s: &str) -> String {
s.lines().next().unwrap_or("").trim().to_string()
}
pub fn get_builtin_flow(name: &str) -> Option<&'static str> {
BUILTIN_FLOWS.get(name).copied()
}
pub fn get_builtin_goal(name: &str) -> Option<&'static str> {
BUILTIN_GOALS.get(name).copied()
}
pub fn resolve_builtin_step(name: &str) -> Option<&'static str> {
if let Some((key, _)) = BUILTIN_STEPS.get_key_value(name) {
return Some(key);
}
resolve_bare_in_map(name, &BUILTIN_STEPS)
}
pub fn resolve_builtin_flow(name: &str) -> Option<&'static str> {
if let Some((key, _)) = BUILTIN_FLOWS.get_key_value(name) {
return Some(key);
}
resolve_bare_in_map(name, &BUILTIN_FLOWS)
}
pub fn resolve_builtin_goal(name: &str) -> Option<&'static str> {
if let Some((key, _)) = BUILTIN_GOALS.get_key_value(name) {
return Some(key);
}
resolve_bare_in_map(name, &BUILTIN_GOALS)
}
fn resolve_bare_in_map(
bare: &str,
map: &std::collections::HashMap<&'static str, &'static str>,
) -> Option<&'static str> {
if bare.contains('/') {
return None;
}
let suffix = format!("/{bare}");
let mut matches = map.keys().filter(|key| key.ends_with(&suffix)).copied();
let first = matches.next()?;
if matches.next().is_some() {
None
} else {
Some(first)
}
}
pub fn get_builtin_direction(name: &str) -> Option<&'static str> {
BUILTIN_DIRECTIONS.get(name).copied()
}
pub fn get_builtin_ops_prompt(name: &str) -> Option<&'static str> {
BUILTIN_OPS_PROMPTS.get(name).copied()
}
pub fn builtin_step_names() -> Vec<&'static str> {
BUILTIN_STEPS.keys().copied().collect()
}
pub fn builtin_flow_names() -> Vec<&'static str> {
BUILTIN_FLOWS.keys().copied().collect()
}
pub fn builtin_flow_entries() -> impl Iterator<Item = (&'static str, &'static str)> {
BUILTIN_FLOWS.iter().map(|(k, v)| (*k, *v))
}
pub fn builtin_direction_names() -> Vec<&'static str> {
BUILTIN_DIRECTIONS.keys().copied().collect()
}
pub fn builtin_direction_group(name: &str) -> Option<&'static Vec<&'static str>> {
BUILTIN_DIRECTION_GROUPS.get(name)
}
pub fn builtin_direction_group_names() -> Vec<&'static str> {
BUILTIN_DIRECTION_GROUPS.keys().copied().collect()
}
include!(concat!(env!("OUT_DIR"), "/builtin_steps.rs"));
include!(concat!(env!("OUT_DIR"), "/builtin_flows.rs"));
include!(concat!(env!("OUT_DIR"), "/builtin_goals.rs"));
include!(concat!(env!("OUT_DIR"), "/builtin_flow_categories.rs"));
include!(concat!(env!("OUT_DIR"), "/builtin_step_categories.rs"));
include!(concat!(env!("OUT_DIR"), "/builtin_directions.rs"));
include!(concat!(env!("OUT_DIR"), "/builtin_direction_groups.rs"));
include!(concat!(env!("OUT_DIR"), "/builtin_ops_prompts.rs"));
#[cfg(test)]
mod tests {
use super::*;
const WAVE_AUTHORING_DOC: &str = include_str!("../../../../docs/wave-authoring.md");
#[test]
fn wave_model_is_embedded_in_prompts_and_docs() {
let update_wave = get_builtin_step("update-wave").expect("update-wave prompt");
let design = get_builtin_step("design").expect("design prompt");
let scan_waves = get_builtin_step("scan").expect("scan prompt");
let split_wave = get_builtin_step("split-wave").expect("split-wave prompt");
assert!(update_wave.contains("lf op pm"));
assert!(update_wave.contains("MEMORY.md"));
assert!(!update_wave.contains("1-fix-broken-build.md"));
assert!(design.contains("lf op pm"));
assert!(design.contains("GOAL.md"));
assert!(!design.contains("1-*.md"));
assert!(scan_waves.contains("lf op pm show"));
assert!(split_wave.contains("lf op pm"));
assert!(WAVE_AUTHORING_DOC.contains("GOAL.md"));
assert!(WAVE_AUTHORING_DOC.contains("Linear"));
assert!(!WAVE_AUTHORING_DOC.contains("1-fix-crash-loop.md"));
assert!(get_builtin_step("ingest").is_none());
}
#[test]
fn vsm_system_goals_are_registered() {
let key = resolve_builtin_goal("s3").expect("s3 goal");
let goal = get_builtin_goal(key).expect("registered goal");
assert_eq!(key, "s3");
assert!(goal.contains("True north: the whole is worth more than the sum of its parts."));
}
}