lwc 0.17.11

Agent-driven proactive memory CLI for AI agents — autonomously recall, maintain, and evolve persistent, source-grounded knowledge across sessions.
use serde_json::Value;
use std::{fs, process::Command};

const OFFICECLI_VERSION: &str = "v1.0.144";

fn officecli_target() -> &'static str {
    match (std::env::consts::OS, std::env::consts::ARCH) {
        ("macos", "aarch64") => "mac-arm64",
        ("macos", "x86_64") => "mac-x64",
        ("linux", "aarch64") => "linux-arm64",
        ("linux", "x86_64") => "linux-x64",
        ("windows", "aarch64") => "win-arm64",
        ("windows", "x86_64") => "win-x64",
        pair => panic!("unsupported test platform {pair:?}"),
    }
}

fn officecli_asset() -> String {
    format!(
        "officecli-{}{}",
        officecli_target(),
        if cfg!(windows) { ".exe" } else { "" }
    )
}

fn officecli_sha256() -> &'static str {
    match officecli_target() {
        "mac-arm64" => "04757163428c5bde8d91e8f838517818e74722157722ca5f3877b6716b77bd45",
        "mac-x64" => "366100643d757b0da24829422897ca74768a894b5ecd1a471a1336f8e2a0787d",
        "linux-arm64" => "56ec2c3114b66f6490888b6778cbb8413a65911a26cacc7207f29e13424966da",
        "linux-x64" => "32ef7a21a54a4ca6c9806bf5e9f3d32bfb1291017329c55044cb2aac71822eb8",
        "win-arm64" => "0adb928d118e237b108077dadca9e272c236cd378c699712a41adda697047860",
        "win-x64" => "e780cc6a5385f84b4d54d71b0c179904ed534125ec33fe39b1a8711fa80e387e",
        target => panic!("unsupported OfficeCLI target {target}"),
    }
}

fn officecli_runtime(home: &std::path::Path) -> std::path::PathBuf {
    home.join(".lwc/runtime/officecli")
        .join(OFFICECLI_VERSION)
        .join(officecli_target())
}

#[test]
fn office_is_disabled_without_a_project_or_runtime_side_effects() {
    let temp = tempfile::tempdir().unwrap();
    let cwd = temp.path().join("cwd");
    let home = temp.path().join("home");
    fs::create_dir_all(&cwd).unwrap();
    fs::create_dir_all(&home).unwrap();

    let output = Command::new(env!("CARGO_BIN_EXE_lwc"))
        .current_dir(&cwd)
        .env("HOME", &home)
        .args(["office", "view", "report.docx", "text"])
        .output()
        .unwrap();

    assert!(!output.status.success());
    let error: Value = serde_json::from_slice(&output.stderr).unwrap();
    assert_eq!(error["error"]["code"], "office_disabled");
    assert_eq!(
        error["error"]["details"]["configure"],
        "lwc --scope global config set --office officecli"
    );
    assert!(!home.join(".lwc/runtime/officecli").exists());
    assert!(!cwd.join(".lwc").exists());
}

#[test]
fn office_configuration_is_global_only_and_does_not_download() {
    let temp = tempfile::tempdir().unwrap();
    let project = temp.path().join("project");
    let home = temp.path().join("home");
    fs::create_dir_all(&project).unwrap();
    fs::create_dir_all(&home).unwrap();

    let init_global = Command::new(env!("CARGO_BIN_EXE_lwc"))
        .current_dir(&project)
        .env("HOME", &home)
        .args(["--scope", "global", "init"])
        .output()
        .unwrap();
    assert!(init_global.status.success());

    let enabled = Command::new(env!("CARGO_BIN_EXE_lwc"))
        .current_dir(&project)
        .env("HOME", &home)
        .args([
            "--scope",
            "global",
            "config",
            "set",
            "--office",
            "officecli",
        ])
        .output()
        .unwrap();
    assert!(
        enabled.status.success(),
        "{}",
        String::from_utf8_lossy(&enabled.stderr)
    );
    let config: Value = serde_json::from_slice(&enabled.stdout).unwrap();
    assert_eq!(config["office"]["setting"], "officecli");
    assert_eq!(config["office"]["origin"], "global");
    assert!(!home.join(".lwc/runtime/officecli").exists());

    let init_project = Command::new(env!("CARGO_BIN_EXE_lwc"))
        .current_dir(&project)
        .env("HOME", &home)
        .arg("init")
        .output()
        .unwrap();
    assert!(init_project.status.success());
    let rejected = Command::new(env!("CARGO_BIN_EXE_lwc"))
        .current_dir(&project)
        .env("HOME", &home)
        .args(["config", "set", "--office", "disabled"])
        .output()
        .unwrap();
    assert!(!rejected.status.success());
    let error: Value = serde_json::from_slice(&rejected.stderr).unwrap();
    assert_eq!(error["error"]["code"], "office_config_global_only");
}

#[test]
fn office_rejects_write_commands_before_installing_a_runtime() {
    let temp = tempfile::tempdir().unwrap();
    let cwd = temp.path().join("cwd");
    let home = temp.path().join("home");
    fs::create_dir_all(&cwd).unwrap();
    fs::create_dir_all(home.join(".lwc")).unwrap();
    fs::write(
        home.join(".lwc/config.json"),
        r#"{"version":4,"office":"officecli"}"#,
    )
    .unwrap();

    for verb in [
        "create",
        "set",
        "add",
        "remove",
        "move",
        "swap",
        "refresh",
        "batch",
        "merge",
        "raw-set",
        "add-part",
        "import",
        "save",
        "open",
        "close",
        "watch",
        "unwatch",
        "goto",
        "load_skill",
        "plugins",
        "mcp",
        "install",
        "config",
    ] {
        let output = Command::new(env!("CARGO_BIN_EXE_lwc"))
            .current_dir(&cwd)
            .env("HOME", &home)
            .args(["office", verb])
            .output()
            .unwrap();
        assert!(!output.status.success(), "{verb} unexpectedly succeeded");
        let error: Value = serde_json::from_slice(&output.stderr).unwrap();
        assert_eq!(
            error["error"]["code"], "office_command_not_read_only",
            "unexpected error for {verb}: {error}"
        );
    }
    assert!(!home.join(".lwc/runtime/officecli").exists());
}

#[cfg(unix)]
#[test]
fn office_forwards_read_commands_without_a_wiki_or_output_wrapping() {
    use std::os::unix::fs::PermissionsExt;

    let temp = tempfile::tempdir().unwrap();
    let cwd = temp.path().join("cwd");
    let home = temp.path().join("home");
    fs::create_dir_all(&cwd).unwrap();
    fs::create_dir_all(home.join(".lwc")).unwrap();
    fs::write(
        home.join(".lwc/config.json"),
        r#"{"version":4,"office":"officecli"}"#,
    )
    .unwrap();
    let runtime = officecli_runtime(&home);
    fs::create_dir_all(&runtime).unwrap();
    let binary = runtime.join("officecli");
    fs::write(
        &binary,
        "#!/bin/sh\nprintf 'stdout:%s|%s|%s|%s\\n' \"$*\" \"$OFFICECLI_SKIP_UPDATE\" \"$OFFICECLI_NO_AUTO_RESIDENT\" \"$PWD\"\nprintf 'stderr:%s\\n' \"$1\" >&2\n[ \"$1\" != query ]\n",
    )
    .unwrap();
    let mut permissions = fs::metadata(&binary).unwrap().permissions();
    permissions.set_mode(0o755);
    fs::set_permissions(&binary, permissions).unwrap();
    fs::write(
        runtime.join("runtime.json"),
        serde_json::to_vec_pretty(&serde_json::json!({
            "version": OFFICECLI_VERSION,
            "target": officecli_target(),
            "asset": officecli_asset(),
            "sha256": officecli_sha256(),
            "binary": "officecli",
        }))
        .unwrap(),
    )
    .unwrap();

    let success = Command::new(env!("CARGO_BIN_EXE_lwc"))
        .current_dir(&cwd)
        .env("HOME", &home)
        .args(["office", "view", "report.docx", "text", "--max-lines", "5"])
        .output()
        .unwrap();
    assert!(success.status.success());
    assert_eq!(
        String::from_utf8(success.stdout).unwrap(),
        format!(
            "stdout:view report.docx text --max-lines 5|1|1|{}\n",
            cwd.canonicalize().unwrap().display()
        )
    );
    assert_eq!(String::from_utf8(success.stderr).unwrap(), "stderr:view\n");

    let failure = Command::new(env!("CARGO_BIN_EXE_lwc"))
        .current_dir(&cwd)
        .env("HOME", &home)
        .args(["office", "query", "report.docx", "paragraph"])
        .output()
        .unwrap();
    assert_eq!(failure.status.code(), Some(1));
    assert!(
        String::from_utf8(failure.stdout)
            .unwrap()
            .starts_with("stdout:query ")
    );
    assert_eq!(String::from_utf8(failure.stderr).unwrap(), "stderr:query\n");
}

#[cfg(all(unix, debug_assertions))]
#[test]
fn office_lazily_installs_once_and_reuses_the_global_runtime() {
    use sha2::{Digest, Sha256};
    use std::os::unix::fs::PermissionsExt;

    let temp = tempfile::tempdir().unwrap();
    let cwd = temp.path().join("cwd");
    let home = temp.path().join("home");
    let fake_bin = temp.path().join("bin");
    fs::create_dir_all(&cwd).unwrap();
    fs::create_dir_all(home.join(".lwc")).unwrap();
    fs::create_dir_all(&fake_bin).unwrap();
    fs::write(
        home.join(".lwc/config.json"),
        r#"{"version":4,"office":"officecli"}"#,
    )
    .unwrap();

    let asset = temp.path().join(officecli_asset());
    fs::write(&asset, "#!/bin/sh\nprintf 'downloaded:%s\\n' \"$*\"\n").unwrap();
    let sha256 = Sha256::digest(fs::read(&asset).unwrap())
        .iter()
        .map(|byte| format!("{byte:02x}"))
        .collect::<String>();
    let count = temp.path().join("downloads");
    let curl = fake_bin.join("curl");
    fs::write(
        &curl,
        "#!/bin/sh\nout=''\nwhile [ \"$#\" -gt 0 ]; do\n  [ \"$1\" = --output ] && { shift; out=$1; }\n  shift\ndone\ncp \"$LWC_TEST_OFFICECLI_ASSET\" \"$out\"\nprintf 'download\\n' >> \"$LWC_TEST_OFFICECLI_COUNT\"\n",
    )
    .unwrap();
    let mut permissions = fs::metadata(&curl).unwrap().permissions();
    permissions.set_mode(0o755);
    fs::set_permissions(&curl, permissions).unwrap();
    let path = format!(
        "{}:{}",
        fake_bin.display(),
        std::env::var("PATH").unwrap_or_default()
    );

    let run = || {
        Command::new(env!("CARGO_BIN_EXE_lwc"))
            .current_dir(&cwd)
            .env("HOME", &home)
            .env("PATH", &path)
            .env("LWC_TEST_OFFICECLI_RELEASE_ROOT", "https://example.invalid")
            .env("LWC_TEST_OFFICECLI_SHA256", &sha256)
            .env("LWC_TEST_OFFICECLI_ASSET", &asset)
            .env("LWC_TEST_OFFICECLI_COUNT", &count)
            .args(["office", "view", "report.docx", "text"])
            .output()
            .unwrap()
    };

    for _ in 0..2 {
        let output = run();
        assert!(
            output.status.success(),
            "{}",
            String::from_utf8_lossy(&output.stderr)
        );
        assert_eq!(
            String::from_utf8(output.stdout).unwrap(),
            "downloaded:view report.docx text\n"
        );
    }
    assert_eq!(fs::read_to_string(&count).unwrap(), "download\n");
    assert!(officecli_runtime(&home).join("runtime.json").is_file());
    assert!(officecli_runtime(&home).join("officecli").is_file());

    let bad_home = temp.path().join("bad-home");
    fs::create_dir_all(bad_home.join(".lwc")).unwrap();
    fs::write(
        bad_home.join(".lwc/config.json"),
        r#"{"version":4,"office":"officecli"}"#,
    )
    .unwrap();
    let rejected = Command::new(env!("CARGO_BIN_EXE_lwc"))
        .current_dir(&cwd)
        .env("HOME", &bad_home)
        .env("PATH", &path)
        .env("LWC_TEST_OFFICECLI_RELEASE_ROOT", "https://example.invalid")
        .env("LWC_TEST_OFFICECLI_SHA256", "0".repeat(64))
        .env("LWC_TEST_OFFICECLI_ASSET", &asset)
        .env("LWC_TEST_OFFICECLI_COUNT", &count)
        .args(["office", "view", "report.docx", "text"])
        .output()
        .unwrap();
    assert!(!rejected.status.success());
    let error: Value = serde_json::from_slice(&rejected.stderr).unwrap();
    assert_eq!(error["error"]["code"], "office_checksum_mismatch");
    assert!(!officecli_runtime(&bad_home).exists());
}