Skip to main content

lean_ctx_patterns/
emspace.rs

1// SPDX-License-Identifier: Apache-2.0
2//! emspace CLI output.
3//!
4//! Page bodies are what an agent edits with `page edit` anchors, so they are
5//! never touched: only the metadata header of a single `page show` is
6//! shortened. JSON, `--body`, `schema` and `run` output are verbatim data
7//! (`shell::compress::classification`) and do not reach this compressor;
8//! everything else (listings, `status`, `orient`) is returned unchanged by the
9//! caller, since emspace output is owned here (`patterns::has_vcs_owner`).
10//! Collapsing listing padding was measured and saved no tokens: the
11//! tokenizer encodes runs of spaces as one token.
12
13macro_rules! static_regex {
14    ($pattern:expr_2021) => {{
15        static RE: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
16        RE.get_or_init(|| {
17            regex::Regex::new($pattern).expect(concat!("BUG: invalid static regex: ", $pattern))
18        })
19    }};
20}
21
22const BODY_MARKER: &str = "--- body ---";
23
24pub fn compress(command: &str, output: &str) -> Option<String> {
25    let words: Vec<&str> = command.split_whitespace().collect();
26    if words.iter().any(|w| *w == "--json" || *w == "--body") {
27        return None;
28    }
29    match words.get(1..3) {
30        Some(["page", "show"]) => compress_page_show(&words[3..], output),
31        _ => None,
32    }
33}
34
35/// One page's header without the lines an agent does not act on (ids and
36/// timestamps other than `updated`, an empty `staleAfter`, the revision
37/// count), and each source as `ok` or its two hashes when it moved. The
38/// `head rN` line stays: `page revise --base rN` needs it. Everything from
39/// the body marker on is copied byte for byte. Several slugs are left alone,
40/// since a body cannot be told from the next page's header.
41fn compress_page_show(operands: &[&str], output: &str) -> Option<String> {
42    let slugs = operands.iter().filter(|w| !w.starts_with('-')).count();
43    if slugs != 1 {
44        return None;
45    }
46    let body_at = output.find(BODY_MARKER)?;
47    let (header, body) = output.split_at(body_at);
48    let source =
49        static_regex!(r"^(\s*)(derived|cites)\s+(.+?)\s+pinned\s+(\S+)\s+observed\s+(\S+)\s*$");
50    let mut out = String::with_capacity(output.len());
51    let mut dropped = 0usize;
52    for line in header.lines() {
53        let key = line.split_whitespace().next().unwrap_or("");
54        let drop = matches!(key, "id" | "created" | "checked" | "revisions")
55            || (key == "staleAfter" && line.trim_end().ends_with('—'));
56        if drop && line.starts_with(key) {
57            dropped += 1;
58            continue;
59        }
60        if let Some(caps) = source.captures(line) {
61            let (pinned, observed) = (&caps[4], &caps[5]);
62            if pinned == observed {
63                out.push_str(&format!("{}{} {} ok\n", &caps[1], &caps[2], &caps[3]));
64            } else {
65                out.push_str(&format!(
66                    "{}{} {} MOVED pinned {pinned} observed {observed}\n",
67                    &caps[1], &caps[2], &caps[3]
68                ));
69            }
70            continue;
71        }
72        out.push_str(line);
73        out.push('\n');
74    }
75    if dropped == 0 && out.len() + 1 >= header.len() {
76        return None;
77    }
78    if dropped > 0 {
79        out.push_str(&super::elision_marker(dropped));
80        out.push('\n');
81    }
82    out.push_str(body);
83    Some(out)
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    // A raw string: a `\` line continuation would strip the indentation that
91    // source lines and body code carry.
92    const PAGE: &str = r"core/adaptive  [draft]  module
93Core: Adaptive Compression Tuning
94Tuning knobs
95
96id          01a18c6c197b031533dc2e02
97created     2026-10-30T10:47:37.081Z
98updated     2026-10-30T12:26:48.855Z
99checked     2026-10-30T12:06:14.583Z
100staleAfter  —
101head        r2 by claude-code/2.1.314 at 2026-10-30T12:06:14.583Z
102revisions   2
103
104sources:
105  derived  dir:repo/rust/src/core/adaptive*.rs       pinned 7f79fb345a07  observed 7f79fb345a07
106  derived  dir:repo/scripts (shape)                  pinned 8148d4fea2ce  observed 19161d63a636
107
108--- body ---
109# Core: Adaptive Compression Tuning
110
111id          this line is body text and stays
112    indented   code   stays   too
113";
114
115    #[test]
116    fn page_show_keeps_the_body_byte_exact_and_the_head_line() {
117        let out = compress("emspace page show core/adaptive", PAGE).unwrap();
118        let body_at = PAGE.find(BODY_MARKER).unwrap();
119        assert!(out.ends_with(&PAGE[body_at..]), "body changed:\n{out}");
120        assert!(out.contains("head        r2 by"));
121        assert!(out.contains("updated     2026-10-30T12:26:48.855Z"));
122        for gone in [
123            "01a18c6c197b",
124            "created ",
125            "checked ",
126            "staleAfter",
127            "revisions ",
128        ] {
129            assert!(
130                !out[..out.find(BODY_MARKER).unwrap()].contains(gone),
131                "{gone}"
132            );
133        }
134        assert!(out.contains("  derived dir:repo/rust/src/core/adaptive*.rs ok\n"));
135        assert!(out.contains(
136            "  derived dir:repo/scripts (shape) MOVED pinned 8148d4fea2ce observed 19161d63a636\n"
137        ));
138        assert!(out.contains(&super::super::elision_marker(5)));
139        assert!(out.len() < PAGE.len());
140    }
141
142    #[test]
143    fn data_forms_and_several_pages_are_left_alone() {
144        assert_eq!(
145            compress("emspace page show core/adaptive --json", PAGE),
146            None
147        );
148        assert_eq!(
149            compress("emspace page show --body core/adaptive", PAGE),
150            None
151        );
152        assert_eq!(compress("emspace page show a b", PAGE), None);
153        assert_eq!(compress("emspace schema pages", "type X = 1;   // c"), None);
154        assert_eq!(compress("emspace page show x", "no marker here"), None);
155    }
156
157    #[test]
158    fn listings_and_writes_are_left_alone() {
159        let list = "core/budget#tests          [draft]  module    Core: Budgets\n";
160        for command in [
161            "emspace search budget --limit 4",
162            "emspace task list",
163            "emspace status",
164            "emspace note add x",
165        ] {
166            assert_eq!(compress(command, list), None, "{command}");
167        }
168    }
169}