feat: migrate repository and workdir domains to ServerApi

This commit is contained in:
2026-09-23 06:51:05 +09:00
parent 6d65d50ec1
commit 7a975765ac
22 changed files with 6711 additions and 261 deletions
+1
View File
@@ -13,6 +13,7 @@ async-trait.workspace = true
fs-operation.workspace = true
manifest.workspace = true
reqwest = { version = "0.13", default-features = false, features = ["json", "rustls"], optional = true }
schemars.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
sha2.workspace = true
+9 -8
View File
@@ -5,6 +5,7 @@
//! optional so Runtime servers can share these DTOs without depending on a
//! client stack.
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{
@@ -16,7 +17,7 @@ use crate::{
};
/// Opaque Runtime-owned identifier for one ephemeral Workdir session.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(transparent)]
pub struct WorkdirSessionId(String);
@@ -37,7 +38,7 @@ impl WorkdirSessionId {
}
/// Open a fresh session for a persisted Workdir identity.
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct OpenWorkdirSessionRequest {
/// Optional Runtime Worker whose persisted binding establishes workspace
/// ownership of the Workdir. Runtime servers reject cross-workspace owners.
@@ -45,7 +46,7 @@ pub struct OpenWorkdirSessionRequest {
pub owner_worker_id: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct OpenWorkdirSessionResponse {
pub session_id: WorkdirSessionId,
pub workdir_id: WorkdirId,
@@ -53,7 +54,7 @@ pub struct OpenWorkdirSessionResponse {
}
/// One provider-side Workdir operation.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(
tag = "operation",
content = "request",
@@ -77,14 +78,14 @@ pub enum WorkdirSessionOperation {
}
/// Wire envelope for one provider operation.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WorkdirSessionOperationRequest {
pub operation: WorkdirSessionOperation,
}
/// Typed result paired with [`WorkdirSessionOperation`].
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(
tag = "operation",
content = "result",
@@ -174,7 +175,7 @@ pub async fn dispatch_workdir_session_operation(
}
/// Stable, host-path-free error code crossing the Runtime boundary.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum WorkdirTransportErrorCode {
NotFound,
@@ -238,7 +239,7 @@ impl WorkdirTransportErrorCode {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct WorkdirTransportError {
pub code: WorkdirTransportErrorCode,
pub message: String,
+5 -4
View File
@@ -20,6 +20,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use async_trait::async_trait;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast;
@@ -45,7 +46,7 @@ pub use scope::{
};
/// Persistent, opaque identity of one materialized Workdir.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
pub struct Workdir {
id: WorkdirId,
}
@@ -63,7 +64,7 @@ impl Workdir {
}
/// Opaque Workdir identifier assigned by the materialization authority.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(transparent)]
pub struct WorkdirId(String);
@@ -79,7 +80,7 @@ impl std::fmt::Display for WorkdirId {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum WorkdirSessionCapability {
Read,
@@ -90,7 +91,7 @@ pub enum WorkdirSessionCapability {
Command,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct WorkdirSessionCapabilities {
bits: u8,
}
+22 -9
View File
@@ -1,15 +1,18 @@
use std::path::PathBuf;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(transparent)]
pub struct CommandHandle(pub String);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CommandRequest {
pub command: String,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
pub timeout_secs: u64,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
pub output_limit: usize,
/// Workdir-relative command directory. Providers validate it against the
/// active session before process start.
@@ -25,15 +28,17 @@ pub struct CommandRequest {
pub tool_call_id: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CommandOutputRequest {
pub handle: CommandHandle,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
pub cursor: usize,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
pub limit: usize,
pub wait: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CommandStatus {
Running,
@@ -43,35 +48,41 @@ pub enum CommandStatus {
Cancelled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CommandStream {
Stdout,
Stderr,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
pub struct CommandStreamSlice {
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
pub start_offset: u64,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
pub end_offset: u64,
pub content: String,
pub truncated: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CommandSnapshot {
pub command_id: String,
pub tool_call_id: Option<String>,
pub status: CommandStatus,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
pub started_at_ms: u64,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
pub observed_at_ms: u64,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
pub last_output_at_ms: Option<u64>,
pub stdout: CommandStreamSlice,
pub stderr: CommandStreamSlice,
#[schemars(range(min = -2147483648_i32, max = 2147483647_i32))]
pub exit_code: Option<i32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum CommandEvent {
Started {
@@ -97,12 +108,14 @@ pub enum CommandEvent {
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CommandOutput {
pub status: CommandStatus,
#[schemars(range(min = -2147483648_i32, max = 2147483647_i32))]
pub exit_code: Option<i32>,
pub timed_out: bool,
pub content: String,
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
pub next_cursor: Option<usize>,
pub truncated: bool,
/// Complete output retained by the provider when `truncated` is true.
+7 -5
View File
@@ -9,6 +9,7 @@ use fs_operation::{
ListResult, ReadRequest, ReadResult, StatRequest, StatResult, WriteRequest, WriteResult,
};
use manifest::SymlinkPolicy;
use schemars::JsonSchema;
use tokio::sync::broadcast;
const MAX_SCOPED_COMMANDS: usize = 16;
@@ -19,25 +20,26 @@ use crate::{
WorkdirSessionCapabilities, WorkdirSessionCapability, WorkdirSessionHandle,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum WorkdirToolScopePermission {
Read,
Write,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WorkdirToolScopeRule {
pub target: FsPath,
pub permission: WorkdirToolScopePermission,
pub recursive: bool,
#[serde(default)]
#[schemars(with = "String")]
pub symlink_policy: SymlinkPolicy,
}
/// Provider-side check for one operation under an attenuated tool scope.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WorkdirScopeAuthorizationRequest {
pub rules: Vec<WorkdirToolScopeRule>,
@@ -46,14 +48,14 @@ pub struct WorkdirScopeAuthorizationRequest {
}
/// Provider-side overlap comparison that keeps resolved host paths private.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WorkdirScopeOverlapRequest {
pub left: WorkdirToolScopeRule,
pub right: WorkdirToolScopeRule,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WorkdirToolScope {
pub rules: Vec<WorkdirToolScopeRule>,
+15 -12
View File
@@ -4,9 +4,10 @@
//! transport projections. They intentionally do not expose provider/session
//! handles, host paths, Runtime URLs, or credentials.
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum WorkingDirectoryMaterializerKind {
#[default]
@@ -14,7 +15,7 @@ pub enum WorkingDirectoryMaterializerKind {
ClientHostedExternal,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum WorkingDirectoryStatusKind {
Active,
@@ -42,7 +43,7 @@ impl std::fmt::Display for WorkingDirectoryStatusKind {
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct WorkingDirectoryCleanupTarget {
pub kind: String,
@@ -50,7 +51,7 @@ pub struct WorkingDirectoryCleanupTarget {
pub repository_key: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct WorkingDirectoryOccupancy {
pub runtime_id: String,
@@ -59,7 +60,7 @@ pub struct WorkingDirectoryOccupancy {
pub linked_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct RuntimeWorkingDirectoryCleanupTarget {
pub kind: String,
@@ -67,7 +68,7 @@ pub struct RuntimeWorkingDirectoryCleanupTarget {
pub repository_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct RuntimeWorkingDirectorySummary {
pub working_directory_id: String,
@@ -99,14 +100,14 @@ pub struct RuntimeWorkingDirectorySummary {
pub occupied_by: Option<WorkingDirectoryOccupancy>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
pub enum WorkingDirectorySource {
Repository { repository_key: String },
ExternalGrant { grant_id: String },
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct WorkingDirectorySummary {
pub working_directory_id: String,
@@ -146,7 +147,9 @@ impl WorkingDirectorySummary {
pub use WorkingDirectoryMaterializerKind as MaterializerKind;
/// Stable Workspace identity for a Worker hosted by a Runtime.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
)]
#[serde(deny_unknown_fields)]
pub struct RuntimeWorkerRef {
pub runtime_id: String,
@@ -164,7 +167,7 @@ impl RuntimeWorkerRef {
}
/// Immutable materialization provenance retained by Workspace inventory.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WorkingDirectoryProvenance {
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -179,7 +182,7 @@ pub struct WorkingDirectoryProvenance {
}
/// Latest provider-neutral observation attached to Workspace inventory.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WorkingDirectoryCurrentObservation {
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -247,7 +250,7 @@ mod tests {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct WorkspaceWorkdirSessionOperationRequest {
/// Worker-local attachment alias selected by the calling tool router.