Skip to main content

agent_doc/
lib.rs

1//! # Module: lib (agent_doc)
2//!
3//! ## Spec
4//! - Exposes the public API surface consumed by the CLI binary, FFI layer, and editor plugins.
5//! - Re-exports: `component`, `crdt`, `debounce`, `ffi`, `frontmatter`, `merge`, `project_config`, `template`.
6//! - `component::strip_comments(content)` is the shared entry point for comment stripping,
7//!   usable by both the binary (`diff::compute`) and external crates (`eval-runner`).
8//! - Provides two boundary-ID utilities used across all write paths:
9//!   - `new_boundary_id()` — 8-hex-char UUID v4 prefix (length controlled by `BOUNDARY_ID_LEN`).
10//!   - `new_boundary_id_with_summary(summary)` — same ID optionally suffixed with a 3-word,
11//!     20-char-max slug derived from `summary` (format: `a0cfeb34:boundary-fix`).
12//! - `format_boundary_marker(id)` — renders the canonical HTML comment form
13//!   `<!-- agent:boundary:<id> -->` used in document component boundaries.
14//! - `BOUNDARY_ID_LEN = 8` is a public constant; callers may read but should not override.
15//!
16//! ## Agentic Contracts
17//! - All public symbols are safe to call from FFI consumers (JNA, napi-rs) via `ffi` module.
18//! - `new_boundary_id` is non-deterministic (UUID v4); callers must not rely on ordering.
19//! - `new_boundary_id_with_summary(None)` and `new_boundary_id_with_summary(Some(""))` both
20//!   return a plain 8-char ID with no suffix.
21//! - Slug derivation: lowercase, non-alphanumeric chars → `-`, collapse runs, take first 3 words,
22//!   truncate to 20 chars.
23//!
24//! ## Evals
25//! - new_boundary_id_len: result is exactly `BOUNDARY_ID_LEN` chars of hex
26//! - new_boundary_id_with_summary_none: `None` summary → plain 8-char hex
27//! - new_boundary_id_with_summary_empty: `Some("")` → plain 8-char hex
28//! - new_boundary_id_with_summary_slug: `Some("Boundary Fix")` → `"<id>:boundary-fix"`
29//! - new_boundary_id_with_summary_truncate: long summary → slug capped at 20 chars
30//! - format_boundary_marker: `"abc123"` → `"<!-- agent:boundary:abc123 -->"`
31
32pub mod component;
33pub mod crdt;
34pub mod debounce;
35pub mod ffi;
36pub mod frontmatter;
37pub mod ipc_socket;
38pub mod merge;
39pub mod model_tier;
40pub mod project_config;
41pub mod template;
42
43/// Default number of hex characters for boundary IDs.
44pub const BOUNDARY_ID_LEN: usize = 8;
45
46/// Generate a new boundary ID (short hex string from UUID v4).
47pub fn new_boundary_id() -> String {
48    let full = uuid::Uuid::new_v4().to_string().replace('-', "");
49    full[..BOUNDARY_ID_LEN.min(full.len())].to_string()
50}
51
52/// Generate a boundary ID with an optional summary suffix.
53///
54/// Format: `a0cfeb34` or `a0cfeb34:boundary-fix` (with summary).
55/// The summary is slugified (lowercase, non-alphanumeric → `-`, max 20 chars).
56pub fn new_boundary_id_with_summary(summary: Option<&str>) -> String {
57    let id = new_boundary_id();
58    match summary {
59        Some(s) if !s.is_empty() => {
60            let slug: String = s.to_lowercase()
61                .chars()
62                .map(|c| if c.is_alphanumeric() { c } else { '-' })
63                .collect::<String>()
64                .split('-')
65                .filter(|s| !s.is_empty())
66                .take(3) // max 3 words
67                .collect::<Vec<&str>>()
68                .join("-");
69            let slug = &slug[..slug.len().min(20)];
70            format!("{}:{}", id, slug)
71        }
72        _ => id,
73    }
74}
75
76/// Format a boundary marker comment.
77pub fn format_boundary_marker(id: &str) -> String {
78    format!("<!-- agent:boundary:{} -->", id)
79}