Skip to main content

roder_protocol/
methods.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
4#[serde(rename_all = "camelCase")]
5pub struct AppServerMethodSpec {
6    pub method: &'static str,
7    pub params_type: String,
8    pub result_type: String,
9    pub stability: AppServerMethodStability,
10    pub feature_group: &'static str,
11    pub idempotency: AppServerIdempotency,
12    pub side_effect: AppServerSideEffect,
13    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
14    pub notifications: &'static [&'static str],
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase")]
19pub enum AppServerMethodStability {
20    Stable,
21    Experimental,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub enum AppServerIdempotency {
27    Idempotent,
28    NonIdempotent,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub enum AppServerSideEffect {
34    ReadOnly,
35    LocalState,
36    ExternalProcess,
37}
38
39#[derive(Debug, Clone, PartialEq, Serialize)]
40#[serde(rename_all = "camelCase")]
41pub struct AppServerMethodManifest {
42    pub schema_version: u32,
43    pub unknown_methods_allowed: bool,
44    pub methods: Vec<AppServerMethodSpec>,
45}
46
47pub const APP_SERVER_METHOD_MANIFEST_VERSION: u32 = 1;
48
49pub fn app_server_method_manifest() -> AppServerMethodManifest {
50    AppServerMethodManifest {
51        schema_version: APP_SERVER_METHOD_MANIFEST_VERSION,
52        unknown_methods_allowed: true,
53        methods: app_server_method_specs(),
54    }
55}
56
57pub fn app_server_method_specs() -> Vec<AppServerMethodSpec> {
58    METHOD_SPECS
59        .iter()
60        .map(|seed| AppServerMethodSpec {
61            method: seed.method,
62            params_type: method_type_name(seed.method, "Params"),
63            result_type: method_type_name(seed.method, "Result"),
64            stability: seed.stability,
65            feature_group: seed.feature_group,
66            idempotency: seed.idempotency,
67            side_effect: seed.side_effect,
68            notifications: seed.notifications,
69        })
70        .collect()
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74struct AppServerMethodSpecSeed {
75    method: &'static str,
76    stability: AppServerMethodStability,
77    feature_group: &'static str,
78    idempotency: AppServerIdempotency,
79    side_effect: AppServerSideEffect,
80    notifications: &'static [&'static str],
81}
82
83fn method_type_name(method: &str, suffix: &str) -> String {
84    if let Some(name) = explicit_method_type_name(method, suffix) {
85        return name.to_string();
86    }
87    let mut name = String::new();
88    let mut capitalize_next = true;
89    for ch in method.chars() {
90        if ch.is_ascii_alphanumeric() {
91            if capitalize_next {
92                name.push(ch.to_ascii_uppercase());
93                capitalize_next = false;
94            } else {
95                name.push(ch);
96            }
97        } else {
98            capitalize_next = true;
99        }
100    }
101    name.push_str(suffix);
102    name
103}
104
105fn explicit_method_type_name(method: &str, suffix: &str) -> Option<&'static str> {
106    match (method, suffix) {
107        ("vcs/status", "Params") | ("vcs/lines/list", "Params") => Some("VcsWorkspaceParams"),
108        ("vcs/status", "Result") => Some("VcsStatus"),
109        ("vcs/changes/read", "Result") => Some("VcsChangedContentPage"),
110        ("vcs/lines/list", "Result") => Some("Vec<VcsLineOfWork>"),
111        ("vcs/lines/switch", "Params") => Some("VcsLineSwitchParams"),
112        ("vcs/lines/switch", "Result")
113        | ("vcs/restore", "Result")
114        | ("vcs/select", "Result")
115        | ("vcs/sync", "Result") => Some("VcsOperationResult"),
116        ("vcs/select", "Params") => Some("VcsSelectionParams"),
117        ("vcs/snapshot/create", "Result") => Some("VcsSnapshot"),
118        _ => None,
119    }
120}
121
122macro_rules! method_spec {
123    ($method:literal, $group:literal, $effect:ident, $idem:ident) => {
124        AppServerMethodSpecSeed {
125            method: $method,
126            stability: AppServerMethodStability::Stable,
127            feature_group: $group,
128            idempotency: AppServerIdempotency::$idem,
129            side_effect: AppServerSideEffect::$effect,
130            notifications: &[],
131        }
132    };
133    ($method:literal, $group:literal, $effect:ident, $idem:ident, [$($notification:literal),+ $(,)?]) => {
134        AppServerMethodSpecSeed {
135            method: $method,
136            stability: AppServerMethodStability::Stable,
137            feature_group: $group,
138            idempotency: AppServerIdempotency::$idem,
139            side_effect: AppServerSideEffect::$effect,
140            notifications: &[$($notification),+],
141        }
142    };
143}
144
145const METHOD_SPECS: &[AppServerMethodSpecSeed] = &[
146    method_spec!("agents/list", "agents", ReadOnly, Idempotent),
147    method_spec!("artifact/delete", "artifacts", LocalState, NonIdempotent),
148    method_spec!("artifact/grep", "artifacts", ReadOnly, Idempotent),
149    method_spec!("artifact/list", "artifacts", ReadOnly, Idempotent),
150    method_spec!("artifact/read", "artifacts", ReadOnly, Idempotent),
151    method_spec!("artifact/tail", "artifacts", ReadOnly, Idempotent),
152    method_spec!("auth/codex/login", "auth", ExternalProcess, NonIdempotent),
153    method_spec!("auth/codex/logout", "auth", LocalState, NonIdempotent),
154    method_spec!("auth/codex/status", "auth", ReadOnly, Idempotent),
155    method_spec!(
156        "auth/supergrok/login",
157        "auth",
158        ExternalProcess,
159        NonIdempotent
160    ),
161    method_spec!("auth/supergrok/logout", "auth", LocalState, NonIdempotent),
162    method_spec!("auth/supergrok/status", "auth", ReadOnly, Idempotent),
163    method_spec!(
164        "automations/cancelRun",
165        "automations",
166        LocalState,
167        NonIdempotent
168    ),
169    method_spec!(
170        "automations/create",
171        "automations",
172        LocalState,
173        NonIdempotent
174    ),
175    method_spec!(
176        "automations/delete",
177        "automations",
178        LocalState,
179        NonIdempotent
180    ),
181    method_spec!("automations/list", "automations", ReadOnly, Idempotent),
182    method_spec!(
183        "automations/runNow",
184        "automations",
185        LocalState,
186        NonIdempotent
187    ),
188    method_spec!("automations/runs", "automations", ReadOnly, Idempotent),
189    method_spec!("automations/status", "automations", ReadOnly, Idempotent),
190    method_spec!(
191        "automations/update",
192        "automations",
193        LocalState,
194        NonIdempotent
195    ),
196    method_spec!("chrome/browsers/list", "chrome", ReadOnly, Idempotent),
197    method_spec!("chrome/debug/console", "chrome", ReadOnly, Idempotent),
198    method_spec!("chrome/debug/network", "chrome", ReadOnly, Idempotent),
199    method_spec!("chrome/disable", "chrome", LocalState, NonIdempotent),
200    method_spec!("chrome/enable", "chrome", LocalState, NonIdempotent),
201    method_spec!(
202        "chrome/page/action",
203        "chrome",
204        ExternalProcess,
205        NonIdempotent
206    ),
207    method_spec!("chrome/page/snapshot", "chrome", ReadOnly, Idempotent),
208    method_spec!("chrome/permissions/list", "chrome", ReadOnly, Idempotent),
209    method_spec!(
210        "chrome/permissions/update",
211        "chrome",
212        LocalState,
213        NonIdempotent
214    ),
215    method_spec!("chrome/reconnect", "chrome", ReadOnly, Idempotent),
216    method_spec!("chrome/setMode", "chrome", LocalState, NonIdempotent),
217    method_spec!("chrome/status", "chrome", ReadOnly, Idempotent),
218    method_spec!(
219        "chrome/tabs/activate",
220        "chrome",
221        ExternalProcess,
222        NonIdempotent
223    ),
224    method_spec!("chrome/tabs/list", "chrome", ReadOnly, Idempotent),
225    method_spec!(
226        "chrome/tabs/navigate",
227        "chrome",
228        ExternalProcess,
229        NonIdempotent
230    ),
231    method_spec!("command/exec", "commands", ExternalProcess, NonIdempotent),
232    method_spec!("commands/expand", "commands", ReadOnly, Idempotent),
233    method_spec!("commands/list", "commands", ReadOnly, Idempotent),
234    method_spec!("commands/run", "commands", LocalState, NonIdempotent),
235    method_spec!("design/batch_get", "design", ReadOnly, Idempotent),
236    method_spec!(
237        "design/export_nodes",
238        "design",
239        LocalState,
240        NonIdempotent,
241        ["design/exportCompleted"]
242    ),
243    method_spec!("design/get_editor_state", "design", ReadOnly, Idempotent),
244    method_spec!("design/get_guidelines", "design", ReadOnly, Idempotent),
245    method_spec!("design/get_screenshot", "design", ReadOnly, Idempotent),
246    method_spec!("design/get_variables", "design", ReadOnly, Idempotent),
247    method_spec!(
248        "design/patch",
249        "design",
250        LocalState,
251        NonIdempotent,
252        ["design/documentChanged"]
253    ),
254    method_spec!("design/read", "design", ReadOnly, Idempotent),
255    method_spec!(
256        "design/set_selection",
257        "design",
258        LocalState,
259        NonIdempotent,
260        ["design/selectionChanged"]
261    ),
262    method_spec!(
263        "design/set_variables",
264        "design",
265        LocalState,
266        NonIdempotent,
267        ["design/documentChanged"]
268    ),
269    method_spec!("design/snapshot_layout", "design", ReadOnly, Idempotent),
270    method_spec!("design/spawn_agents", "design", ReadOnly, NonIdempotent),
271    method_spec!("discovery/groups", "discovery", ReadOnly, Idempotent),
272    method_spec!("discovery/promote", "discovery", LocalState, NonIdempotent),
273    method_spec!(
274        "discovery/promoted/clear",
275        "discovery",
276        LocalState,
277        NonIdempotent
278    ),
279    method_spec!("discovery/promoted/list", "discovery", ReadOnly, Idempotent),
280    method_spec!("discovery/read", "discovery", ReadOnly, Idempotent),
281    method_spec!("discovery/refresh", "discovery", LocalState, NonIdempotent),
282    method_spec!("discovery/search", "discovery", ReadOnly, Idempotent),
283    method_spec!("eval/report/read", "eval", ReadOnly, Idempotent),
284    method_spec!("eval/reports/list", "eval", ReadOnly, Idempotent),
285    method_spec!("extensions/list", "extensions", ReadOnly, Idempotent),
286    method_spec!("forks/create", "forks", LocalState, NonIdempotent),
287    method_spec!("forks/list", "forks", ReadOnly, Idempotent),
288    method_spec!("forks/providers/list", "forks", ReadOnly, Idempotent),
289    method_spec!("forks/remove", "forks", LocalState, NonIdempotent),
290    method_spec!("fs/readDirectory", "filesystem", ReadOnly, Idempotent),
291    method_spec!("fs/readFile", "filesystem", ReadOnly, Idempotent),
292    method_spec!("hosted/audit/list", "hosted", ReadOnly, Idempotent),
293    method_spec!("hosted/hooks/create", "hosted", LocalState, NonIdempotent),
294    method_spec!("hosted/hooks/delete", "hosted", LocalState, NonIdempotent),
295    method_spec!("hosted/hooks/list", "hosted", ReadOnly, Idempotent),
296    method_spec!("hosted/hooks/update", "hosted", LocalState, NonIdempotent),
297    method_spec!(
298        "hosted/service_accounts/create",
299        "hosted",
300        LocalState,
301        NonIdempotent
302    ),
303    method_spec!(
304        "hosted/service_accounts/list",
305        "hosted",
306        ReadOnly,
307        Idempotent
308    ),
309    method_spec!(
310        "hosted/service_accounts/revoke",
311        "hosted",
312        LocalState,
313        NonIdempotent
314    ),
315    method_spec!("hosted/tenant/read", "hosted", ReadOnly, Idempotent),
316    method_spec!("hosted/tenants/list", "hosted", ReadOnly, Idempotent),
317    method_spec!("hosted/usage/read", "hosted", ReadOnly, Idempotent),
318    method_spec!("hosted/whoami", "hosted", ReadOnly, Idempotent),
319    method_spec!("hunk/list", "plan-review", ReadOnly, Idempotent),
320    method_spec!("hunk/read", "plan-review", ReadOnly, Idempotent),
321    method_spec!("hunk/rollback", "plan-review", LocalState, NonIdempotent),
322    method_spec!("index/proofs/list", "code-index", ReadOnly, Idempotent),
323    method_spec!("index/readChunk", "code-index", ReadOnly, Idempotent),
324    method_spec!("index/rebuild", "code-index", LocalState, NonIdempotent),
325    method_spec!("index/search", "code-index", ReadOnly, Idempotent),
326    method_spec!("index/status", "code-index", ReadOnly, Idempotent),
327    method_spec!(
328        "inference/routing/metrics",
329        "inference",
330        ReadOnly,
331        Idempotent
332    ),
333    method_spec!(
334        "inference/routing/status",
335        "inference",
336        ReadOnly,
337        Idempotent
338    ),
339    method_spec!("initialize", "app", ReadOnly, Idempotent),
340    method_spec!("knowledge/delete", "knowledge", LocalState, NonIdempotent),
341    method_spec!(
342        "knowledge/links/set",
343        "knowledge",
344        LocalState,
345        NonIdempotent
346    ),
347    method_spec!("knowledge/list", "knowledge", ReadOnly, Idempotent),
348    method_spec!("knowledge/read", "knowledge", ReadOnly, Idempotent),
349    method_spec!(
350        "knowledge/revisions/list",
351        "knowledge",
352        ReadOnly,
353        Idempotent
354    ),
355    method_spec!("knowledge/save", "knowledge", LocalState, NonIdempotent),
356    method_spec!("knowledge/search", "knowledge", ReadOnly, Idempotent),
357    method_spec!("knowledge/update", "knowledge", LocalState, NonIdempotent),
358    method_spec!(
359        "marketplaces/add",
360        "marketplaces",
361        LocalState,
362        NonIdempotent
363    ),
364    method_spec!(
365        "marketplaces/install_default",
366        "marketplaces",
367        LocalState,
368        NonIdempotent
369    ),
370    method_spec!("marketplaces/list", "marketplaces", ReadOnly, Idempotent),
371    method_spec!("marketplaces/plugin", "marketplaces", ReadOnly, Idempotent),
372    method_spec!(
373        "marketplaces/refresh",
374        "marketplaces",
375        LocalState,
376        NonIdempotent
377    ),
378    method_spec!(
379        "marketplaces/remove",
380        "marketplaces",
381        LocalState,
382        NonIdempotent
383    ),
384    method_spec!("marketplaces/search", "marketplaces", ReadOnly, Idempotent),
385    method_spec!("media/attachToTurn", "media", LocalState, NonIdempotent),
386    method_spec!("media/delete", "media", LocalState, NonIdempotent),
387    method_spec!("media/image/generate", "media", LocalState, NonIdempotent),
388    method_spec!("media/image/providers/list", "media", ReadOnly, Idempotent),
389    method_spec!("media/list", "media", ReadOnly, Idempotent),
390    method_spec!("media/read", "media", ReadOnly, Idempotent),
391    method_spec!("media/thumbnail", "media", ReadOnly, Idempotent),
392    method_spec!("memory/delete", "memory", LocalState, NonIdempotent),
393    method_spec!("memory/list", "memory", ReadOnly, Idempotent),
394    method_spec!("memory/provider/list", "memory", ReadOnly, Idempotent),
395    method_spec!("memory/provider/set", "memory", LocalState, NonIdempotent),
396    method_spec!("memory/query", "memory", ReadOnly, Idempotent),
397    method_spec!("memory/read", "memory", ReadOnly, Idempotent),
398    method_spec!("memory/recall/preview", "memory", ReadOnly, Idempotent),
399    method_spec!("memory/save", "memory", LocalState, NonIdempotent),
400    method_spec!("memory/update", "memory", LocalState, NonIdempotent),
401    method_spec!("model/list", "models", ReadOnly, Idempotent),
402    method_spec!("model/select", "models", LocalState, NonIdempotent),
403    method_spec!("node/status", "node", ReadOnly, Idempotent),
404    method_spec!(
405        "packages/approve_extensions",
406        "packages",
407        LocalState,
408        NonIdempotent
409    ),
410    method_spec!(
411        "packages/install",
412        "packages",
413        ExternalProcess,
414        NonIdempotent
415    ),
416    method_spec!("packages/list", "packages", ReadOnly, Idempotent),
417    method_spec!("packages/remove", "packages", LocalState, NonIdempotent),
418    method_spec!(
419        "packages/set_enabled",
420        "packages",
421        LocalState,
422        NonIdempotent
423    ),
424    method_spec!(
425        "packages/set_filters",
426        "packages",
427        LocalState,
428        NonIdempotent
429    ),
430    method_spec!("packages/sync", "packages", ExternalProcess, NonIdempotent),
431    method_spec!(
432        "packages/update",
433        "packages",
434        ExternalProcess,
435        NonIdempotent
436    ),
437    method_spec!(
438        "plan/review/approve",
439        "plan-review",
440        LocalState,
441        NonIdempotent
442    ),
443    method_spec!(
444        "plan/review/comment",
445        "plan-review",
446        LocalState,
447        NonIdempotent
448    ),
449    method_spec!("plan/review/read", "plan-review", ReadOnly, Idempotent),
450    method_spec!(
451        "plan/review/reject",
452        "plan-review",
453        LocalState,
454        NonIdempotent
455    ),
456    method_spec!(
457        "plan/review/rewrite",
458        "plan-review",
459        LocalState,
460        NonIdempotent
461    ),
462    method_spec!("plugins/disable", "plugins", LocalState, NonIdempotent),
463    method_spec!("plugins/install", "plugins", LocalState, NonIdempotent),
464    method_spec!(
465        "plugins/install_all_variants",
466        "plugins",
467        LocalState,
468        NonIdempotent
469    ),
470    method_spec!("plugins/list_installed", "plugins", ReadOnly, Idempotent),
471    method_spec!("plugins/preview_install", "plugins", ReadOnly, Idempotent),
472    method_spec!("plugins/uninstall", "plugins", LocalState, NonIdempotent),
473    method_spec!("processes/get", "processes", ReadOnly, Idempotent),
474    method_spec!("processes/list", "processes", ReadOnly, Idempotent),
475    method_spec!("processes/stop", "processes", LocalState, NonIdempotent),
476    method_spec!("processes/stopAll", "processes", LocalState, NonIdempotent),
477    method_spec!(
478        "processes/subscribe",
479        "processes",
480        ReadOnly,
481        Idempotent,
482        ["processes/changed"]
483    ),
484    method_spec!("providers/clear", "providers", LocalState, NonIdempotent),
485    method_spec!(
486        "providers/configure",
487        "providers",
488        LocalState,
489        NonIdempotent
490    ),
491    method_spec!("providers/list", "providers", ReadOnly, Idempotent),
492    method_spec!("providers/select", "providers", LocalState, NonIdempotent),
493    method_spec!("retrieval/metrics", "retrieval", ReadOnly, Idempotent),
494    method_spec!("retrieval/promoted", "retrieval", ReadOnly, Idempotent),
495    method_spec!(
496        "retrieval/recommendations",
497        "retrieval",
498        ReadOnly,
499        Idempotent
500    ),
501    method_spec!("roadmap/create", "roadmap", LocalState, NonIdempotent),
502    method_spec!("roadmap/list", "roadmap", ReadOnly, Idempotent),
503    method_spec!("roadmap/patch", "roadmap", LocalState, NonIdempotent),
504    method_spec!("roadmap/read", "roadmap", ReadOnly, Idempotent),
505    method_spec!("roadmap/task/update", "roadmap", LocalState, NonIdempotent),
506    method_spec!(
507        "roadmap/thread/attach",
508        "roadmap",
509        LocalState,
510        NonIdempotent
511    ),
512    method_spec!("roadmap/thread/list", "roadmap", ReadOnly, Idempotent),
513    method_spec!(
514        "roadmap/thread/spawn",
515        "roadmap",
516        ExternalProcess,
517        NonIdempotent
518    ),
519    method_spec!("roadmap/validate", "roadmap", ReadOnly, Idempotent),
520    method_spec!("runners/delete", "runners", LocalState, NonIdempotent),
521    method_spec!("runners/list", "runners", ReadOnly, Idempotent),
522    method_spec!("runners/ports", "runners", ReadOnly, Idempotent),
523    method_spec!("runners/select", "runners", LocalState, NonIdempotent),
524    method_spec!("runners/session", "runners", ReadOnly, Idempotent),
525    method_spec!("runners/snapshot", "runners", ReadOnly, Idempotent),
526    method_spec!(
527        "search_index/clear",
528        "search-index",
529        LocalState,
530        NonIdempotent
531    ),
532    method_spec!(
533        "search_index/rebuild",
534        "search-index",
535        LocalState,
536        NonIdempotent
537    ),
538    method_spec!("search_index/status", "search-index", ReadOnly, Idempotent),
539    method_spec!(
540        "search_index/warmup",
541        "search-index",
542        LocalState,
543        NonIdempotent
544    ),
545    method_spec!("settings/get", "settings", ReadOnly, Idempotent),
546    method_spec!(
547        "settings/set_default_mode",
548        "settings",
549        LocalState,
550        NonIdempotent
551    ),
552    method_spec!(
553        "settings/set_file_backed_dynamic_context",
554        "settings",
555        LocalState,
556        NonIdempotent
557    ),
558    method_spec!(
559        "settings/set_search_index",
560        "settings",
561        LocalState,
562        NonIdempotent
563    ),
564    method_spec!("settings/set_shell", "settings", LocalState, NonIdempotent),
565    method_spec!(
566        "settings/set_web_search",
567        "settings",
568        LocalState,
569        NonIdempotent
570    ),
571    method_spec!("skills/list", "skills", ReadOnly, Idempotent),
572    method_spec!("skills/read", "skills", ReadOnly, Idempotent),
573    method_spec!("skills/setEnabled", "skills", LocalState, NonIdempotent),
574    method_spec!("skills/setExposure", "skills", LocalState, NonIdempotent),
575    method_spec!("speech/providers/list", "speech", ReadOnly, Idempotent),
576    method_spec!(
577        "speech/synthesis/providers/list",
578        "speech",
579        ReadOnly,
580        Idempotent
581    ),
582    method_spec!(
583        "speech/synthesize",
584        "speech",
585        ExternalProcess,
586        NonIdempotent
587    ),
588    method_spec!(
589        "speech/transcribe",
590        "speech",
591        ExternalProcess,
592        NonIdempotent
593    ),
594    method_spec!("stats/backfill", "stats", LocalState, NonIdempotent),
595    method_spec!("stats/export", "stats", LocalState, NonIdempotent),
596    method_spec!("stats/sessions", "stats", ReadOnly, Idempotent),
597    method_spec!("stats/summary", "stats", ReadOnly, Idempotent),
598    method_spec!("stats/tokens", "stats", ReadOnly, Idempotent),
599    method_spec!("stats/tools", "stats", ReadOnly, Idempotent),
600    method_spec!("tasks/cancel", "tasks", LocalState, NonIdempotent),
601    method_spec!("tasks/get", "tasks", ReadOnly, Idempotent),
602    method_spec!("tasks/list", "tasks", ReadOnly, Idempotent),
603    method_spec!("tasks/submit", "tasks", LocalState, NonIdempotent),
604    method_spec!(
605        "tasks/subscribe",
606        "tasks",
607        ReadOnly,
608        Idempotent,
609        [
610            "task.started",
611            "task.output",
612            "task.completed",
613            "task.failed",
614            "task.cancelled",
615        ]
616    ),
617    method_spec!("team/cleanup", "teams", LocalState, NonIdempotent),
618    method_spec!("team/list", "teams", ReadOnly, Idempotent),
619    method_spec!("team/member/focus", "teams", LocalState, NonIdempotent),
620    method_spec!("team/member/interrupt", "teams", LocalState, NonIdempotent),
621    method_spec!("team/member/message", "teams", LocalState, NonIdempotent),
622    method_spec!("team/member/start", "teams", LocalState, NonIdempotent),
623    method_spec!("team/pane/cleanup", "teams", LocalState, NonIdempotent),
624    method_spec!("team/pane/focus", "teams", LocalState, NonIdempotent),
625    method_spec!("team/read", "teams", ReadOnly, Idempotent),
626    method_spec!("team/start", "teams", LocalState, NonIdempotent),
627    method_spec!("thread/archive", "thread", LocalState, NonIdempotent),
628    method_spec!("thread/attach", "thread", LocalState, NonIdempotent),
629    method_spec!("thread/exit_plan", "thread", LocalState, NonIdempotent),
630    method_spec!("thread/fork", "thread", LocalState, NonIdempotent),
631    method_spec!("thread/fork_status", "thread", ReadOnly, Idempotent),
632    method_spec!(
633        "thread/goal/clear",
634        "thread",
635        LocalState,
636        NonIdempotent,
637        ["thread/goal/cleared"]
638    ),
639    method_spec!("thread/goal/get", "thread", ReadOnly, Idempotent),
640    method_spec!(
641        "thread/goal/set",
642        "thread",
643        LocalState,
644        NonIdempotent,
645        ["thread/goal/updated"]
646    ),
647    method_spec!("thread/list", "thread", ReadOnly, Idempotent),
648    method_spec!("thread/read", "thread", ReadOnly, Idempotent),
649    method_spec!("thread/remove_fork", "thread", LocalState, NonIdempotent),
650    method_spec!(
651        "thread/resolve_approval",
652        "thread",
653        LocalState,
654        NonIdempotent
655    ),
656    method_spec!(
657        "thread/resolve_user_input",
658        "thread",
659        LocalState,
660        NonIdempotent
661    ),
662    method_spec!("thread/roadmap/open", "thread", LocalState, NonIdempotent),
663    method_spec!("thread/set_mode", "thread", LocalState, NonIdempotent),
664    method_spec!("thread/start", "thread", LocalState, NonIdempotent),
665    method_spec!("thread/state", "thread", ReadOnly, Idempotent),
666    method_spec!("tools/call", "tools", LocalState, NonIdempotent),
667    method_spec!("tools/list", "tools", ReadOnly, Idempotent),
668    method_spec!("tools/resolve", "tools", LocalState, NonIdempotent),
669    method_spec!("turn/interrupt", "turns", LocalState, NonIdempotent),
670    method_spec!("turn/start", "turns", LocalState, NonIdempotent),
671    method_spec!("turn/steer", "turns", LocalState, NonIdempotent),
672    method_spec!("turn/subagentTrace/read", "turns", ReadOnly, Idempotent),
673    method_spec!("turn/subagentTraces/list", "turns", ReadOnly, Idempotent),
674    method_spec!("vcs/changes/list", "vcs", ReadOnly, Idempotent),
675    method_spec!("vcs/changes/read", "vcs", ReadOnly, Idempotent),
676    method_spec!("vcs/lines/list", "vcs", ReadOnly, Idempotent),
677    method_spec!("vcs/lines/switch", "vcs", LocalState, NonIdempotent),
678    method_spec!("vcs/restore", "vcs", LocalState, NonIdempotent),
679    method_spec!("vcs/select", "vcs", LocalState, NonIdempotent),
680    method_spec!("vcs/snapshot/create", "vcs", LocalState, NonIdempotent),
681    method_spec!("vcs/status", "vcs", ReadOnly, Idempotent),
682    method_spec!("vcs/sync", "vcs", ExternalProcess, NonIdempotent),
683    method_spec!("webwright/artifacts", "webwright", ReadOnly, Idempotent),
684    method_spec!("webwright/export", "webwright", LocalState, NonIdempotent),
685    method_spec!("webwright/latestRun", "webwright", ReadOnly, Idempotent),
686    method_spec!("webwright/prepare", "webwright", LocalState, NonIdempotent),
687    method_spec!("webwright/report", "webwright", ReadOnly, Idempotent),
688    method_spec!(
689        "webwright/rerun",
690        "webwright",
691        ExternalProcess,
692        NonIdempotent
693    ),
694    method_spec!(
695        "webwright/setup",
696        "webwright",
697        ExternalProcess,
698        NonIdempotent
699    ),
700    method_spec!("webwright/submit", "webwright", LocalState, NonIdempotent),
701    method_spec!("webwright/verify", "webwright", ReadOnly, Idempotent),
702    method_spec!(
703        "webwright/visualJudge",
704        "webwright",
705        LocalState,
706        NonIdempotent
707    ),
708    method_spec!("workflow/enable", "workflow", LocalState, NonIdempotent),
709    method_spec!("workflow/ignore", "workflow", LocalState, NonIdempotent),
710    method_spec!("workflow/preview", "workflow", ReadOnly, Idempotent),
711    method_spec!("workflow/refresh", "workflow", LocalState, NonIdempotent),
712    method_spec!("workflow/remove", "workflow", LocalState, NonIdempotent),
713    method_spec!("workflow/scan", "workflow", ReadOnly, Idempotent),
714    method_spec!(
715        "workflows/approve",
716        "workflows",
717        LocalState,
718        NonIdempotent,
719        [
720            "workflows/approved",
721            "workflows/denied",
722            "workflows/queued",
723            "workflows/started",
724        ]
725    ),
726    method_spec!("workflows/get", "workflows", ReadOnly, Idempotent),
727    method_spec!("workflows/list", "workflows", ReadOnly, Idempotent),
728    method_spec!(
729        "workflows/pause",
730        "workflows",
731        LocalState,
732        NonIdempotent,
733        ["workflows/paused"]
734    ),
735    method_spec!(
736        "workflows/plan",
737        "workflows",
738        LocalState,
739        NonIdempotent,
740        ["workflows/drafted", "workflows/approvalRequested"]
741    ),
742    method_spec!(
743        "workflows/restartAgent",
744        "workflows",
745        LocalState,
746        NonIdempotent,
747        [
748            "workflows/agentQueued",
749            "workflows/agentStarted",
750            "workflows/agentCompleted",
751            "workflows/agentFailed",
752        ]
753    ),
754    method_spec!(
755        "workflows/resume",
756        "workflows",
757        LocalState,
758        NonIdempotent,
759        ["workflows/resumed"]
760    ),
761    method_spec!("workflows/save", "workflows", LocalState, NonIdempotent),
762    method_spec!(
763        "workflows/scripts/delete",
764        "workflows",
765        LocalState,
766        NonIdempotent
767    ),
768    method_spec!("workflows/scripts/list", "workflows", ReadOnly, Idempotent),
769    method_spec!("workflows/scripts/read", "workflows", ReadOnly, Idempotent),
770    method_spec!(
771        "workflows/stop",
772        "workflows",
773        LocalState,
774        NonIdempotent,
775        ["workflows/stopped"]
776    ),
777    method_spec!(
778        "workspace/changes/list",
779        "workspace",
780        ReadOnly,
781        Idempotent,
782        ["workspace/changeObserved"]
783    ),
784    method_spec!("workspace/create", "workspace", LocalState, NonIdempotent),
785    method_spec!(
786        "workspace/files/children",
787        "workspace-files",
788        ReadOnly,
789        Idempotent
790    ),
791    method_spec!(
792        "workspace/files/query",
793        "workspace-files",
794        ReadOnly,
795        Idempotent
796    ),
797    method_spec!(
798        "workspace/files/read",
799        "workspace-files",
800        ReadOnly,
801        Idempotent
802    ),
803    method_spec!(
804        "workspace/files/rebuild",
805        "workspace-files",
806        LocalState,
807        NonIdempotent,
808        ["workspace/files/statusChanged"]
809    ),
810    method_spec!(
811        "workspace/files/status",
812        "workspace-files",
813        ReadOnly,
814        Idempotent
815    ),
816    method_spec!("workspace/forget", "workspace", LocalState, NonIdempotent),
817    method_spec!("workspace/list", "workspace", ReadOnly, Idempotent),
818    method_spec!("workspace/update", "workspace", LocalState, NonIdempotent),
819];
820
821#[cfg(test)]
822mod tests {
823    use std::collections::BTreeSet;
824
825    use super::*;
826
827    #[test]
828    fn method_manifest_is_sorted_and_unique() {
829        let methods = app_server_method_specs();
830        let names = methods.iter().map(|spec| spec.method).collect::<Vec<_>>();
831        let mut sorted = names.clone();
832        sorted.sort_unstable();
833        assert_eq!(names, sorted);
834
835        let unique = names.iter().copied().collect::<BTreeSet<_>>();
836        assert_eq!(unique.len(), names.len());
837    }
838
839    #[test]
840    fn method_manifest_covers_broad_app_server_surface() {
841        let methods = app_server_method_specs()
842            .iter()
843            .map(|spec| spec.method)
844            .collect::<BTreeSet<_>>();
845        for required in [
846            "providers/list",
847            "settings/get",
848            "thread/start",
849            "turn/start",
850            "thread/resolve_approval",
851            "tools/call",
852            "commands/list",
853            "tasks/submit",
854            "webwright/prepare",
855            "team/member/message",
856            "plan/review/comment",
857            "hunk/rollback",
858            "workflow/scan",
859            "workflows/plan",
860            "marketplaces/search",
861            "plugins/install",
862            "packages/install",
863            "packages/list",
864            "media/list",
865            "memory/query",
866            "automations/list",
867            "processes/list",
868            "speech/providers/list",
869            "speech/synthesis/providers/list",
870            "speech/synthesize",
871            "speech/transcribe",
872            "vcs/status",
873            "vcs/select",
874            "workspace/files/children",
875            "workspace/files/query",
876            "workspace/files/read",
877            "workspace/files/rebuild",
878            "workspace/files/status",
879        ] {
880            assert!(methods.contains(required), "missing {required}");
881        }
882        assert!(!methods.contains("vcs/extras/list"));
883    }
884
885    #[test]
886    fn method_manifest_uses_canonical_vcs_type_names() {
887        let manifest = app_server_method_manifest();
888        let status = manifest
889            .methods
890            .iter()
891            .find(|method| method.method == "vcs/status")
892            .expect("vcs/status method");
893        assert_eq!(status.params_type, "VcsWorkspaceParams");
894        assert_eq!(status.result_type, "VcsStatus");
895
896        let select = manifest
897            .methods
898            .iter()
899            .find(|method| method.method == "vcs/select")
900            .expect("vcs/select method");
901        assert_eq!(select.params_type, "VcsSelectionParams");
902        assert_eq!(select.result_type, "VcsOperationResult");
903    }
904
905    #[test]
906    fn method_manifest_records_subscription_notifications() {
907        let methods = app_server_method_specs();
908        let processes = methods
909            .iter()
910            .find(|spec| spec.method == "processes/subscribe")
911            .expect("processes subscribe spec");
912        assert_eq!(processes.notifications, ["processes/changed"]);
913
914        let tasks = methods
915            .iter()
916            .find(|spec| spec.method == "tasks/subscribe")
917            .expect("tasks subscribe spec");
918        assert!(tasks.notifications.contains(&"task.started"));
919        assert!(tasks.notifications.contains(&"task.completed"));
920
921        let workflows_plan = methods
922            .iter()
923            .find(|spec| spec.method == "workflows/plan")
924            .expect("workflows plan spec");
925        assert!(workflows_plan.notifications.contains(&"workflows/drafted"));
926        assert!(
927            workflows_plan
928                .notifications
929                .contains(&"workflows/approvalRequested")
930        );
931
932        let workspace_files_rebuild = methods
933            .iter()
934            .find(|spec| spec.method == "workspace/files/rebuild")
935            .expect("workspace files rebuild spec");
936        assert_eq!(
937            workspace_files_rebuild.notifications,
938            ["workspace/files/statusChanged"]
939        );
940    }
941}