1use schemars::JsonSchema;
19use serde::{Deserialize, Serialize};
20use serde_json::Value as JsonValue;
21
22use super::{
23 BlockingState, CliSpec, Config, GitPublishMode, GitRevertMode, QueueFile, RunnerApprovalMode,
24 Task,
25};
26
27pub const MACHINE_SYSTEM_INFO_VERSION: u32 = 1;
28pub const MACHINE_QUEUE_READ_VERSION: u32 = 1;
29pub const MACHINE_QUEUE_VALIDATE_VERSION: u32 = 1;
30pub const MACHINE_QUEUE_REPAIR_VERSION: u32 = 1;
31pub const MACHINE_QUEUE_UNDO_VERSION: u32 = 1;
32pub const MACHINE_CONFIG_RESOLVE_VERSION: u32 = 3;
33pub const MACHINE_TASK_CREATE_VERSION: u32 = 1;
34pub const MACHINE_TASK_MUTATION_VERSION: u32 = 2;
35pub const MACHINE_GRAPH_READ_VERSION: u32 = 1;
36pub const MACHINE_DASHBOARD_READ_VERSION: u32 = 1;
37pub const MACHINE_DECOMPOSE_VERSION: u32 = 2;
38pub const MACHINE_RUN_EVENT_VERSION: u32 = 3;
39pub const MACHINE_RUN_SUMMARY_VERSION: u32 = 2;
40pub const MACHINE_DOCTOR_REPORT_VERSION: u32 = 2;
41pub const MACHINE_PARALLEL_STATUS_VERSION: u32 = 2;
42pub const MACHINE_CLI_SPEC_VERSION: u32 = 2;
43pub const MACHINE_ERROR_VERSION: u32 = 1;
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
46#[serde(rename_all = "snake_case")]
47pub enum MachineErrorCode {
48 CliUnavailable,
49 PermissionDenied,
50 ConfigIncompatible,
51 ParseError,
52 NetworkError,
53 QueueCorrupted,
54 ResourceBusy,
55 VersionMismatch,
56 TaskMutationConflict,
57 Unknown,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
61#[serde(deny_unknown_fields)]
62pub struct MachineErrorDocument {
63 pub version: u32,
64 pub code: MachineErrorCode,
65 pub message: String,
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub detail: Option<String>,
68 pub retryable: bool,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
72#[serde(deny_unknown_fields)]
73pub struct MachineSystemInfoDocument {
74 pub version: u32,
75 pub cli_version: String,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
79#[serde(deny_unknown_fields)]
80pub struct MachineQueuePaths {
81 pub repo_root: String,
82 pub queue_path: String,
83 pub done_path: String,
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub project_config_path: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub global_config_path: Option<String>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
91#[serde(deny_unknown_fields)]
92pub struct MachineQueueReadDocument {
93 pub version: u32,
94 pub paths: MachineQueuePaths,
95 pub active: QueueFile,
96 pub done: QueueFile,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub next_runnable_task_id: Option<String>,
99 #[schemars(schema_with = "json_value_schema")]
100 pub runnability: JsonValue,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
104#[serde(deny_unknown_fields)]
105pub struct MachineContinuationAction {
106 pub title: String,
107 pub command: String,
108 pub detail: String,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
112#[serde(deny_unknown_fields)]
113pub struct MachineContinuationSummary {
114 pub headline: String,
115 pub detail: String,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub blocking: Option<BlockingState>,
118 #[serde(default)]
119 pub next_steps: Vec<MachineContinuationAction>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
123#[serde(deny_unknown_fields)]
124pub struct MachineValidationWarning {
125 pub task_id: String,
126 pub message: String,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
130#[serde(deny_unknown_fields)]
131pub struct MachineQueueValidateDocument {
132 pub version: u32,
133 pub valid: bool,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub blocking: Option<BlockingState>,
136 #[serde(default)]
137 pub warnings: Vec<MachineValidationWarning>,
138 pub continuation: MachineContinuationSummary,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
142#[serde(deny_unknown_fields)]
143pub struct MachineQueueRepairDocument {
144 pub version: u32,
145 pub dry_run: bool,
146 pub changed: bool,
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub blocking: Option<BlockingState>,
149 #[schemars(schema_with = "json_value_schema")]
150 pub report: JsonValue,
151 pub continuation: MachineContinuationSummary,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
155#[serde(deny_unknown_fields)]
156pub struct MachineQueueUndoDocument {
157 pub version: u32,
158 pub dry_run: bool,
159 pub restored: bool,
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub blocking: Option<BlockingState>,
162 #[schemars(schema_with = "option_json_value_schema")]
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub result: Option<JsonValue>,
165 pub continuation: MachineContinuationSummary,
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
169#[serde(deny_unknown_fields)]
170pub struct MachineResumeDecision {
171 pub status: String,
172 pub scope: String,
173 pub reason: String,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub task_id: Option<String>,
176 pub message: String,
177 pub detail: String,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
181#[serde(deny_unknown_fields)]
182pub struct MachineConfigResolveDocument {
183 pub version: u32,
184 pub paths: MachineQueuePaths,
185 pub safety: MachineConfigSafetySummary,
186 pub config: Config,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub resume_preview: Option<MachineResumeDecision>,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
192#[serde(deny_unknown_fields)]
193pub struct MachineConfigSafetySummary {
194 pub repo_trusted: bool,
195 pub dirty_repo: bool,
196 pub git_publish_mode: GitPublishMode,
197 #[serde(skip_serializing_if = "Option::is_none")]
198 pub approval_mode: Option<RunnerApprovalMode>,
199 pub ci_gate_enabled: bool,
200 pub git_revert_mode: GitRevertMode,
201 pub parallel_configured: bool,
202 pub execution_interactivity: String,
203 pub interactive_approval_supported: bool,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
207#[serde(deny_unknown_fields)]
208pub struct MachineCliSpecDocument {
209 pub version: u32,
210 pub spec: CliSpec,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
214#[serde(deny_unknown_fields)]
215pub struct MachineTaskCreateRequest {
216 pub version: u32,
217 pub title: String,
218 #[serde(skip_serializing_if = "Option::is_none")]
219 pub description: Option<String>,
220 pub priority: String,
221 #[serde(default)]
222 pub tags: Vec<String>,
223 #[serde(default, skip_serializing_if = "Vec::is_empty")]
224 pub scope: Vec<String>,
225 #[serde(skip_serializing_if = "Option::is_none")]
226 pub template: Option<String>,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub target: Option<String>,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
232#[serde(deny_unknown_fields)]
233pub struct MachineTaskCreateDocument {
234 pub version: u32,
235 pub task: Task,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
239#[serde(deny_unknown_fields)]
240pub struct MachineTaskMutationDocument {
241 pub version: u32,
242 #[serde(skip_serializing_if = "Option::is_none")]
243 pub blocking: Option<BlockingState>,
244 #[schemars(schema_with = "json_value_schema")]
245 pub report: JsonValue,
246 pub continuation: MachineContinuationSummary,
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
250#[serde(deny_unknown_fields)]
251pub struct MachineGraphReadDocument {
252 pub version: u32,
253 #[schemars(schema_with = "json_value_schema")]
254 pub graph: JsonValue,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
258#[serde(deny_unknown_fields)]
259pub struct MachineDashboardReadDocument {
260 pub version: u32,
261 #[schemars(schema_with = "json_value_schema")]
262 pub dashboard: JsonValue,
263}
264
265#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
266#[serde(deny_unknown_fields)]
267pub struct MachineDecomposeDocument {
268 pub version: u32,
269 #[serde(skip_serializing_if = "Option::is_none")]
270 pub blocking: Option<BlockingState>,
271 #[schemars(schema_with = "json_value_schema")]
272 pub result: JsonValue,
273 pub continuation: MachineContinuationSummary,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
277#[serde(deny_unknown_fields)]
278pub struct MachineDoctorReportDocument {
279 pub version: u32,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub blocking: Option<BlockingState>,
282 #[schemars(schema_with = "json_value_schema")]
283 pub report: JsonValue,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
287#[serde(deny_unknown_fields)]
288pub struct MachineParallelStatusDocument {
289 pub version: u32,
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub blocking: Option<BlockingState>,
292 pub continuation: MachineContinuationSummary,
293 #[schemars(schema_with = "json_value_schema")]
294 pub status: JsonValue,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
298#[serde(rename_all = "snake_case")]
299pub enum MachineRunEventKind {
300 RunStarted,
301 QueueSnapshot,
302 ConfigResolved,
303 ResumeDecision,
304 TaskSelected,
305 PhaseEntered,
306 PhaseCompleted,
307 RunnerOutput,
308 BlockedStateChanged,
309 BlockedStateCleared,
310 Warning,
311 RunFinished,
312}
313
314#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
315#[serde(deny_unknown_fields)]
316pub struct MachineRunEventEnvelope {
317 pub version: u32,
318 pub kind: MachineRunEventKind,
319 pub timestamp: String,
320 #[serde(skip_serializing_if = "Option::is_none")]
321 pub run_mode: Option<String>,
322 #[serde(skip_serializing_if = "Option::is_none")]
323 pub task_id: Option<String>,
324 #[serde(skip_serializing_if = "Option::is_none")]
325 pub phase: Option<String>,
326 #[serde(skip_serializing_if = "Option::is_none")]
327 pub exit_code: Option<i32>,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub message: Option<String>,
330 #[serde(skip_serializing_if = "Option::is_none")]
331 pub stream: Option<String>,
332 #[schemars(schema_with = "option_json_value_schema")]
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub payload: Option<JsonValue>,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
338#[serde(deny_unknown_fields)]
339pub struct MachineRunSummaryDocument {
340 pub version: u32,
341 pub task_id: Option<String>,
342 pub exit_code: i32,
343 pub outcome: String,
344 #[serde(skip_serializing_if = "Option::is_none")]
345 pub blocking: Option<BlockingState>,
346}
347
348fn json_value_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
349 <JsonValue as JsonSchema>::json_schema(generator)
350}
351
352fn option_json_value_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
353 <Option<JsonValue> as JsonSchema>::json_schema(generator)
354}