mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 23:32:14 +00:00
File › Scripts › Other Script… picks a .js or .jsx file, shows a warning that can be turned off in Preferences › General, and runs the script against the open documents through the `vc` object. The new `script.run` and `script.stop` commands run and stop a script over MCP. - A run is one transaction. Each document it changed gets one undo step named Run Script. An uncaught error, a limit or a stop puts every document, the paint, the clipboard, menu state and preferences back. - A command that fails inside a run, or whose result is too large to reach the script, is undone and throws an error the script can catch. - Files a command wrote stay on disk and the report names them, also when the run is stopped from the quit question. - While a script runs, other commands that change anything fail with a busy error; MCP reports it as JSON-RPC error -32003. - In the app the run advances one slice per frame with a Stop button in the status bar. A run that adds a great many objects asks whether to continue; Stop and Escape end it. - Commands that change state outside the documents, such as prefs.*, plugin.* and file.place.queue, are refused to scripts. Docs: docs/mcp.md, docs/gaps.md, docs/roadmap.md, docs/target-app-parity.md.
45 lines
1.5 KiB
Rust
45 lines
1.5 KiB
Rust
//! MCP tool definitions (names, descriptions, JSON Schemas) and their implementations on top of a
|
|
//! [`Backend`].
|
|
|
|
use serde_json::{Map, Value, json};
|
|
use vectorcraft_engine::cmd::fileio::{ARTBOARD_PARAMS, FORMATS, OPEN_EXTS, SAVE_FORMATS, format, writable_format};
|
|
|
|
use crate::backend::Backend;
|
|
|
|
mod definitions;
|
|
mod dispatch;
|
|
mod handlers;
|
|
|
|
pub use definitions::tool_definitions;
|
|
#[cfg(test)]
|
|
pub(crate) use dispatch::MAX_COMMAND_BATCH_STEPS;
|
|
pub use dispatch::call_tool;
|
|
pub(crate) use dispatch::check_tool_arguments;
|
|
|
|
/// The result of `tools/call`: MCP content blocks plus the `isError` flag.
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct ToolResult {
|
|
pub content: Vec<Value>,
|
|
pub is_error: bool,
|
|
}
|
|
|
|
impl ToolResult {
|
|
pub fn text(t: impl Into<String>) -> Self {
|
|
Self { content: vec![json!({"type": "text", "text": t.into()})], is_error: false }
|
|
}
|
|
pub fn json(v: &Value) -> Self {
|
|
Self::text(serde_json::to_string_pretty(v).unwrap_or_default())
|
|
}
|
|
pub fn error(t: impl Into<String>) -> Self {
|
|
Self { content: vec![json!({"type": "text", "text": t.into()})], is_error: true }
|
|
}
|
|
pub fn to_value(&self) -> Value {
|
|
json!({"content": self.content, "isError": self.is_error})
|
|
}
|
|
/// The error's text, when the engine refused the call because a script is running.
|
|
pub(crate) fn script_busy(&self) -> Option<String> {
|
|
let text = self.content.first()?.get("text")?.as_str()?;
|
|
(self.is_error && text.ends_with(vectorcraft_engine::SCRIPT_BUSY)).then(|| text.to_string())
|
|
}
|
|
}
|