mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-27 11:57:36 -06:00
- MCP: execute, batch, type_text, select_text, get_text, inspect_document, render_page and save_document take an optional doc (an open document's id); the headless server runs them through Session::with_document and the bridge passes doc to the app. New list_documents tool; new_document replies with the new document's id. Tool descriptions and the server instructions say that file.new and file.open open another document. - Control channel: engine.execute, document.inspect and ui.render take doc and work on that document while the window keeps the active one; file.close on an addressed document refuses unsaved changes unless forced; ui.* commands need the document on screen. ui.inspect reports document and documents. Unknown or malformed ids are errors. - CLI run starts with one open document; help and docs describe how file.new, file.open and view.switchWindows work in a run. - docs/mcp.md and docs/control-protocol.md describe document ids and doc.
40 lines
2.1 KiB
Rust
40 lines
2.1 KiB
Rust
//! `wordcraft-cli run` with documents opened along the way: `file.new` and `file.open` open
|
|
//! another document and make it active, and `--save` saves the active one.
|
|
|
|
use std::path::Path;
|
|
use std::process::{Command, Output};
|
|
|
|
fn run(args: &[&str], out: &Path) -> Output {
|
|
let mut cli = Command::new(env!("CARGO_BIN_EXE_wordcraft-cli"));
|
|
cli.arg("run").args(args).arg("--save").arg(out);
|
|
cli.output().unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn run_saves_the_document_opened_last() {
|
|
let dir = std::env::temp_dir().join(format!("wordcraft-cli-documents-{}", std::process::id()));
|
|
std::fs::create_dir_all(&dir).unwrap();
|
|
let (src, out) = (dir.join("opened.txt"), dir.join("out.txt"));
|
|
std::fs::write(&src, "Opened\n").unwrap();
|
|
let open = format!(r#"file.open={{"path":{}}}"#, serde_json::json!(src.to_string_lossy()));
|
|
|
|
// A script that starts a new document and types into it saves that document.
|
|
let made = run(&["--template", "sample", "--cmd", "file.new", "--cmd", r#"text.insert={"text":"Fresh"}"#], &out);
|
|
let fresh = std::fs::read_to_string(&out).unwrap_or_default();
|
|
// A file opened after typing is what is saved; the typed document stays out of it.
|
|
let opened = run(&["--template", "blank", "--cmd", r#"text.insert={"text":"Typed"}"#, "--cmd", &open, "--cmd", "caret.docEnd"], &out);
|
|
let reopened = std::fs::read_to_string(&out).unwrap_or_default();
|
|
// A run starts with one open document.
|
|
let mut cli = Command::new(env!("CARGO_BIN_EXE_wordcraft-cli"));
|
|
let listed = cli.args(["run", "--template", "sample", "--print", "--cmd", "view.switchWindows"]).output().unwrap();
|
|
let _ = std::fs::remove_dir_all(&dir);
|
|
|
|
assert!(made.status.success(), "stderr: {}", String::from_utf8_lossy(&made.stderr));
|
|
assert_eq!(fresh.trim(), "Fresh");
|
|
assert!(opened.status.success(), "stderr: {}", String::from_utf8_lossy(&opened.stderr));
|
|
assert_eq!(reopened.trim(), "Opened");
|
|
assert!(listed.status.success(), "stderr: {}", String::from_utf8_lossy(&listed.stderr));
|
|
let stdout = String::from_utf8_lossy(&listed.stdout);
|
|
assert_eq!(stdout.matches("\"id\"").count(), 1, "{stdout}");
|
|
}
|