Skip to main content

vtcode_webmcp/
runtime.rs

1use crate::error::Result;
2use crate::protocol::FileChange;
3use async_trait::async_trait;
4use serde::Serialize;
5use std::borrow::Cow;
6
7/// Runtime status exposed to a paired browser.
8#[derive(Debug, Clone, Serialize)]
9pub struct RuntimeStatus {
10    /// Displayed workspace root, never a secret.
11    pub workspace_root: String,
12    /// Whether the bridge has a connected runtime adapter.
13    pub connected: bool,
14    /// Whether the adapter can submit prompts to an agent runtime.
15    pub turns_available: bool,
16    /// Whether mutation requests can be authorized by the runtime.
17    pub mutations_allowed: bool,
18    /// Whether check requests can be authorized by the runtime.
19    pub checks_allowed: bool,
20    /// Human-readable approval authority.
21    pub approval_authority: Cow<'static, str>,
22}
23
24/// A file entry returned by a runtime adapter.
25#[derive(Debug, Clone, Serialize)]
26pub struct WorkspaceFile {
27    /// Workspace-relative path.
28    pub path: String,
29    /// File size in bytes.
30    pub size_bytes: u64,
31    /// SHA-256 digest prefixed with `sha256:`.
32    pub digest: String,
33}
34
35/// File content plus its authoritative digest.
36#[derive(Debug, Clone, Serialize)]
37pub struct FileSnapshot {
38    /// Workspace-relative path.
39    pub path: String,
40    /// UTF-8 file content.
41    pub content: String,
42    /// SHA-256 digest of `content`.
43    pub digest: String,
44}
45
46/// A validated, not-yet-applied proposal.
47#[derive(Debug, Clone, Serialize)]
48pub struct PatchProposal {
49    /// Opaque proposal identity.
50    pub proposal_id: String,
51    /// Structured changes included in the proposal.
52    pub changes: Vec<FileChange>,
53    /// Authoritative unified diff generated by the adapter.
54    pub unified_diff: String,
55}
56
57/// Result of an applied proposal.
58#[derive(Debug, Clone, Serialize)]
59pub struct AppliedChange {
60    /// Opaque identity required for revert.
61    pub change_id: String,
62    /// Paths changed by the proposal.
63    pub paths: Vec<String>,
64}
65
66/// Result of a check command.
67#[derive(Debug, Clone, Serialize)]
68pub struct CheckResult {
69    /// Parsed command text.
70    pub command: String,
71    /// Process exit code, if the process started.
72    pub exit_code: Option<i32>,
73    /// Captured standard output.
74    pub stdout: String,
75    /// Captured standard error.
76    pub stderr: String,
77}
78
79/// Result of a submitted agent turn.
80#[derive(Debug, Clone, Serialize)]
81pub struct TurnResult {
82    /// Runtime-assigned turn identifier.
83    pub turn_id: String,
84    /// Whether the turn was accepted for execution.
85    pub accepted: bool,
86}
87
88/// The runtime boundary used by the WebMCP transport.
89#[async_trait]
90pub trait RuntimeAdapter: Send + Sync {
91    /// Return current workspace and permission state.
92    async fn status(&self) -> Result<RuntimeStatus>;
93
94    /// List files visible to the session.
95    async fn list_files(&self) -> Result<Vec<WorkspaceFile>>;
96
97    /// Read one visible file.
98    async fn read_file(&self, path: &str) -> Result<FileSnapshot>;
99
100    /// Validate and stage a proposal without mutating the workspace.
101    async fn propose_changes(&self, changes: Vec<FileChange>) -> Result<PatchProposal>;
102
103    /// Apply a proposal through the runtime's approval authority.
104    async fn apply_proposal(&self, proposal_id: &str) -> Result<AppliedChange>;
105
106    /// Run a runtime-approved check command.
107    async fn run_checks(&self, command: &str) -> Result<CheckResult>;
108
109    /// Revert a still-current last change.
110    async fn revert_last_change(&self, change_id: &str) -> Result<AppliedChange>;
111
112    /// Submit a prompt and optional validated proposal to the active runtime.
113    async fn request_turn(&self, prompt: &str, proposal_id: Option<&str>) -> Result<TurnResult>;
114
115    /// Cancel a runtime request.
116    ///
117    /// The boolean reports whether an active operation was found and accepted
118    /// for cancellation. Unknown or already-complete identifiers are not
119    /// errors, which keeps reconnecting clients idempotent.
120    async fn cancel(&self, _target_id: &str) -> Result<bool> {
121        Ok(false)
122    }
123}