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