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