Skip to main content

codex/
wrapper_coverage_manifest.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
4#[serde(rename_all = "snake_case")]
5pub enum CoverageLevel {
6    Explicit,
7    Passthrough,
8    Unsupported,
9    IntentionallyUnsupported,
10    Unknown,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub struct WrapperSurfaceScopedTargets {
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub platforms: Option<Vec<String>>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub target_triples: Option<Vec<String>>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
22pub struct WrapperFlagCoverageV1 {
23    pub key: String,
24    pub level: CoverageLevel,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub note: Option<String>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub scope: Option<WrapperSurfaceScopedTargets>,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
32pub struct WrapperArgCoverageV1 {
33    pub name: String,
34    pub level: CoverageLevel,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub note: Option<String>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub scope: Option<WrapperSurfaceScopedTargets>,
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
42pub struct WrapperCommandCoverageV1 {
43    pub path: Vec<String>,
44    pub level: CoverageLevel,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub note: Option<String>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub scope: Option<WrapperSurfaceScopedTargets>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub flags: Option<Vec<WrapperFlagCoverageV1>>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub args: Option<Vec<WrapperArgCoverageV1>>,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56pub struct WrapperCoverageManifestV1 {
57    pub schema_version: u32,
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub generated_at: Option<String>,
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub wrapper_version: Option<String>,
62    pub coverage: Vec<WrapperCommandCoverageV1>,
63}
64
65pub fn wrapper_crate_version() -> &'static str {
66    env!("CARGO_PKG_VERSION")
67}
68
69/// The single source of truth for wrapper coverage declarations.
70///
71/// This value is consumed by `xtask codex-wrapper-coverage` to generate
72/// `cli_manifests/codex/wrapper_coverage.json`.
73pub fn wrapper_coverage_manifest() -> WrapperCoverageManifestV1 {
74    fn flag(key: &str, level: CoverageLevel) -> WrapperFlagCoverageV1 {
75        WrapperFlagCoverageV1 {
76            key: key.to_string(),
77            level,
78            note: None,
79            scope: None,
80        }
81    }
82
83    fn flag_note(key: &str, level: CoverageLevel, note: &str) -> WrapperFlagCoverageV1 {
84        WrapperFlagCoverageV1 {
85            key: key.to_string(),
86            level,
87            note: Some(note.to_string()),
88            scope: None,
89        }
90    }
91
92    fn arg(name: &str, level: CoverageLevel) -> WrapperArgCoverageV1 {
93        WrapperArgCoverageV1 {
94            name: name.to_string(),
95            level,
96            note: None,
97            scope: None,
98        }
99    }
100
101    fn arg_note(name: &str, level: CoverageLevel, note: &str) -> WrapperArgCoverageV1 {
102        WrapperArgCoverageV1 {
103            name: name.to_string(),
104            level,
105            note: Some(note.to_string()),
106            scope: None,
107        }
108    }
109
110    fn command(
111        path: &[&str],
112        level: CoverageLevel,
113        note: Option<&str>,
114        flags: Vec<WrapperFlagCoverageV1>,
115        args: Vec<WrapperArgCoverageV1>,
116    ) -> WrapperCommandCoverageV1 {
117        WrapperCommandCoverageV1 {
118            path: path.iter().map(|s| s.to_string()).collect(),
119            level,
120            note: note.map(|s| s.to_string()),
121            scope: None,
122            flags: (!flags.is_empty()).then_some(flags),
123            args: (!args.is_empty()).then_some(args),
124        }
125    }
126
127    WrapperCoverageManifestV1 {
128        schema_version: 1,
129        generated_at: None,
130        wrapper_version: None,
131        coverage: vec![
132            // Scenario 0: root/global flags and probe flags.
133            command(
134                &[],
135                CoverageLevel::Explicit,
136                None,
137                vec![
138                    flag("--help", CoverageLevel::Explicit),
139                    flag("--version", CoverageLevel::Explicit),
140                    flag("--model", CoverageLevel::Explicit),
141                    flag("--image", CoverageLevel::Explicit),
142                    flag_note("--add-dir", CoverageLevel::Explicit, "capability-guarded"),
143                    flag_note(
144                        "--config",
145                        CoverageLevel::Passthrough,
146                        "Generic config overrides are forwarded as strings; keys are not typed/validated by the wrapper.",
147                    ),
148                    flag_note(
149                        "--enable",
150                        CoverageLevel::Passthrough,
151                        "Generic feature toggles are forwarded as strings; individual feature flags are not typed by the wrapper.",
152                    ),
153                    flag_note(
154                        "--disable",
155                        CoverageLevel::Passthrough,
156                        "Generic feature toggles are forwarded as strings; individual feature flags are not typed by the wrapper.",
157                    ),
158                    flag("--profile", CoverageLevel::Explicit),
159                    flag("--cd", CoverageLevel::Explicit),
160                    flag("--ask-for-approval", CoverageLevel::Explicit),
161                    flag("--sandbox", CoverageLevel::Explicit),
162                    flag("--full-auto", CoverageLevel::Explicit),
163                    flag(
164                        "--dangerously-bypass-approvals-and-sandbox",
165                        CoverageLevel::Explicit,
166                    ),
167                    flag("--local-provider", CoverageLevel::Explicit),
168                    flag("--oss", CoverageLevel::Explicit),
169                    flag("--search", CoverageLevel::Explicit),
170                ],
171                vec![],
172            ),
173            // Scenario 1+2: `codex exec` (single-response + streaming).
174            command(
175                &["exec"],
176                CoverageLevel::Explicit,
177                None,
178                vec![
179                    flag("--color", CoverageLevel::Explicit),
180                    flag("--skip-git-repo-check", CoverageLevel::Explicit),
181                    flag("--json", CoverageLevel::Explicit),
182                    flag("--output-last-message", CoverageLevel::Explicit),
183                    flag_note(
184                        "--output-schema",
185                        CoverageLevel::Explicit,
186                        "capability-guarded",
187                    ),
188                ],
189                vec![arg("PROMPT", CoverageLevel::Explicit)],
190            ),
191            // Scenario 3: `codex exec resume` (streaming resume).
192            command(
193                &["exec", "resume"],
194                CoverageLevel::Explicit,
195                None,
196                vec![
197                    flag("--json", CoverageLevel::Explicit),
198                    flag("--skip-git-repo-check", CoverageLevel::Explicit),
199                    flag("--last", CoverageLevel::Explicit),
200                    flag("--all", CoverageLevel::Explicit),
201                ],
202                vec![
203                    arg("PROMPT", CoverageLevel::Explicit),
204                    arg("SESSION_ID", CoverageLevel::Explicit),
205                ],
206            ),
207            // Scenario 4: `codex apply <TASK_ID>`.
208            command(
209                &["apply"],
210                CoverageLevel::Explicit,
211                None,
212                vec![],
213                vec![arg("TASK_ID", CoverageLevel::Explicit)],
214            ),
215            // Scenario 4: `codex cloud diff <TASK_ID>`.
216            command(
217                &["cloud", "diff"],
218                CoverageLevel::Explicit,
219                None,
220                vec![flag("--attempt", CoverageLevel::Explicit)],
221                vec![arg("TASK_ID", CoverageLevel::Explicit)],
222            ),
223            command(
224                &["cloud", "apply"],
225                CoverageLevel::Explicit,
226                None,
227                vec![flag("--attempt", CoverageLevel::Explicit)],
228                vec![arg("TASK_ID", CoverageLevel::Explicit)],
229            ),
230            command(
231                &["cloud", "status"],
232                CoverageLevel::Explicit,
233                None,
234                vec![],
235                vec![arg("TASK_ID", CoverageLevel::Explicit)],
236            ),
237            command(
238                &["cloud", "list"],
239                CoverageLevel::Explicit,
240                None,
241                vec![
242                    flag("--cursor", CoverageLevel::Explicit),
243                    flag("--env", CoverageLevel::Explicit),
244                    flag("--json", CoverageLevel::Explicit),
245                    flag("--limit", CoverageLevel::Explicit),
246                ],
247                vec![],
248            ),
249            command(
250                &["cloud", "exec"],
251                CoverageLevel::Explicit,
252                None,
253                vec![
254                    flag("--env", CoverageLevel::Explicit),
255                    flag("--attempts", CoverageLevel::Explicit),
256                    flag("--branch", CoverageLevel::Explicit),
257                ],
258                vec![arg("QUERY", CoverageLevel::Explicit)],
259            ),
260            // Scenario 5: login/logout.
261            command(
262                &["login"],
263                CoverageLevel::Explicit,
264                None,
265                vec![
266                    flag_note("--mcp", CoverageLevel::Explicit, "capability-guarded"),
267                    flag("--api-key", CoverageLevel::Explicit),
268                    flag("--device-auth", CoverageLevel::Explicit),
269                    flag("--with-api-key", CoverageLevel::Explicit),
270                ],
271                vec![],
272            ),
273            command(
274                &["login", "status"],
275                CoverageLevel::Explicit,
276                None,
277                vec![],
278                vec![],
279            ),
280            command(&["logout"], CoverageLevel::Explicit, None, vec![], vec![]),
281            // Scenario 6: `codex features list`.
282            command(
283                &["features", "list"],
284                CoverageLevel::Explicit,
285                None,
286                vec![],
287                vec![],
288            ),
289            // Scenario 7: `codex app-server generate-*`.
290            command(
291                &["app-server", "generate-ts"],
292                CoverageLevel::Explicit,
293                None,
294                vec![
295                    flag("--experimental", CoverageLevel::Explicit),
296                    flag("--out", CoverageLevel::Explicit),
297                    flag("--prettier", CoverageLevel::Explicit),
298                ],
299                vec![],
300            ),
301            command(
302                &["app-server", "generate-json-schema"],
303                CoverageLevel::Explicit,
304                None,
305                vec![
306                    flag("--experimental", CoverageLevel::Explicit),
307                    flag("--out", CoverageLevel::Explicit),
308                ],
309                vec![],
310            ),
311            // Scenario 8: `codex responses-api-proxy`.
312            command(
313                &["responses-api-proxy"],
314                CoverageLevel::Explicit,
315                None,
316                vec![
317                    flag("--port", CoverageLevel::Explicit),
318                    flag("--server-info", CoverageLevel::Explicit),
319                    flag("--http-shutdown", CoverageLevel::Explicit),
320                    flag("--upstream-url", CoverageLevel::Explicit),
321                ],
322                vec![],
323            ),
324            // Scenario 9: `codex stdio-to-uds`.
325            command(
326                &["stdio-to-uds"],
327                CoverageLevel::Explicit,
328                None,
329                vec![],
330                vec![arg("SOCKET_PATH", CoverageLevel::Explicit)],
331            ),
332            // Scenario 10: `codex sandbox <platform>`.
333            command(&["sandbox"], CoverageLevel::Explicit, None, vec![], vec![]),
334            command(
335                &["sandbox", "macos"],
336                CoverageLevel::Explicit,
337                None,
338                vec![flag("--log-denials", CoverageLevel::Explicit)],
339                vec![arg("COMMAND", CoverageLevel::Explicit)],
340            ),
341            command(
342                &["sandbox", "linux"],
343                CoverageLevel::Explicit,
344                None,
345                vec![],
346                vec![arg("COMMAND", CoverageLevel::Explicit)],
347            ),
348            command(
349                &["sandbox", "windows"],
350                CoverageLevel::Explicit,
351                None,
352                vec![],
353                vec![arg("COMMAND", CoverageLevel::Explicit)],
354            ),
355            // Scenario 11: `codex execpolicy check`.
356            command(
357                &["execpolicy", "check"],
358                CoverageLevel::Explicit,
359                None,
360                vec![
361                    flag("--policy", CoverageLevel::Explicit),
362                    flag("--pretty", CoverageLevel::Explicit),
363                ],
364                vec![arg("COMMAND", CoverageLevel::Explicit)],
365            ),
366            // Scenario 12: stdio servers.
367            command(
368                &["mcp-server"],
369                CoverageLevel::Explicit,
370                None,
371                vec![],
372                vec![],
373            ),
374            command(
375                &["app-server"],
376                CoverageLevel::Explicit,
377                None,
378                vec![flag("--analytics-default-enabled", CoverageLevel::Explicit)],
379                vec![],
380            ),
381            command(&["cloud"], CoverageLevel::Explicit, None, vec![], vec![]),
382            command(&["mcp"], CoverageLevel::Explicit, None, vec![], vec![]),
383            command(
384                &["mcp", "list"],
385                CoverageLevel::Explicit,
386                None,
387                vec![flag("--json", CoverageLevel::Explicit)],
388                vec![],
389            ),
390            command(
391                &["mcp", "get"],
392                CoverageLevel::Explicit,
393                None,
394                vec![flag("--json", CoverageLevel::Explicit)],
395                vec![arg("NAME", CoverageLevel::Explicit)],
396            ),
397            command(
398                &["mcp", "add"],
399                CoverageLevel::Explicit,
400                None,
401                vec![
402                    flag("--url", CoverageLevel::Explicit),
403                    flag("--bearer-token-env-var", CoverageLevel::Explicit),
404                    flag("--env", CoverageLevel::Explicit),
405                ],
406                vec![
407                    arg("NAME", CoverageLevel::Explicit),
408                    arg("COMMAND", CoverageLevel::Explicit),
409                ],
410            ),
411            command(
412                &["mcp", "remove"],
413                CoverageLevel::Explicit,
414                None,
415                vec![],
416                vec![arg("NAME", CoverageLevel::Explicit)],
417            ),
418            command(
419                &["mcp", "logout"],
420                CoverageLevel::Explicit,
421                None,
422                vec![],
423                vec![arg("NAME", CoverageLevel::Explicit)],
424            ),
425            command(
426                &["mcp", "login"],
427                CoverageLevel::Explicit,
428                None,
429                vec![flag("--scopes", CoverageLevel::Explicit)],
430                vec![arg("NAME", CoverageLevel::Explicit)],
431            ),
432            // `codex help` command family (variadic COMMAND).
433            command(
434                &["help"],
435                CoverageLevel::Explicit,
436                None,
437                vec![],
438                vec![arg("COMMAND", CoverageLevel::Explicit)],
439            ),
440            command(
441                &["exec", "help"],
442                CoverageLevel::Explicit,
443                None,
444                vec![],
445                vec![arg("COMMAND", CoverageLevel::Explicit)],
446            ),
447            command(
448                &["features", "help"],
449                CoverageLevel::Explicit,
450                None,
451                vec![],
452                vec![arg("COMMAND", CoverageLevel::Explicit)],
453            ),
454            command(
455                &["login", "help"],
456                CoverageLevel::Explicit,
457                None,
458                vec![],
459                vec![arg("COMMAND", CoverageLevel::Explicit)],
460            ),
461            command(
462                &["app-server", "help"],
463                CoverageLevel::Explicit,
464                None,
465                vec![],
466                vec![arg("COMMAND", CoverageLevel::Explicit)],
467            ),
468            command(
469                &["sandbox", "help"],
470                CoverageLevel::Explicit,
471                None,
472                vec![],
473                vec![arg("COMMAND", CoverageLevel::Explicit)],
474            ),
475            command(
476                &["cloud", "help"],
477                CoverageLevel::Explicit,
478                None,
479                vec![],
480                vec![arg("COMMAND", CoverageLevel::Explicit)],
481            ),
482            command(
483                &["mcp", "help"],
484                CoverageLevel::Explicit,
485                None,
486                vec![],
487                vec![arg("COMMAND", CoverageLevel::Explicit)],
488            ),
489            // New 0.92.0+ command surfaces.
490            command(&["features"], CoverageLevel::Explicit, None, vec![], vec![]),
491            // New 0.97.0 command surfaces.
492            command(
493                &["features", "enable"],
494                CoverageLevel::Explicit,
495                None,
496                vec![],
497                vec![arg("FEATURE", CoverageLevel::Explicit)],
498            ),
499            command(
500                &["features", "disable"],
501                CoverageLevel::Explicit,
502                None,
503                vec![],
504                vec![arg("FEATURE", CoverageLevel::Explicit)],
505            ),
506            command(&["debug"], CoverageLevel::Explicit, None, vec![], vec![]),
507            command(
508                &["debug", "help"],
509                CoverageLevel::Explicit,
510                None,
511                vec![],
512                vec![arg("COMMAND", CoverageLevel::Explicit)],
513            ),
514            command(
515                &["debug", "app-server"],
516                CoverageLevel::Explicit,
517                None,
518                vec![],
519                vec![],
520            ),
521            command(
522                &["debug", "app-server", "help"],
523                CoverageLevel::Explicit,
524                None,
525                vec![],
526                vec![arg("COMMAND", CoverageLevel::Explicit)],
527            ),
528            command(
529                &["debug", "app-server", "send-message-v2"],
530                CoverageLevel::Explicit,
531                None,
532                vec![],
533                vec![arg("USER_MESSAGE", CoverageLevel::Explicit)],
534            ),
535            command(
536                &["exec", "review"],
537                CoverageLevel::Explicit,
538                None,
539                vec![
540                    flag("--base", CoverageLevel::Explicit),
541                    flag("--commit", CoverageLevel::Explicit),
542                    flag("--json", CoverageLevel::Explicit),
543                    flag("--skip-git-repo-check", CoverageLevel::Explicit),
544                    flag("--title", CoverageLevel::Explicit),
545                    flag("--uncommitted", CoverageLevel::Explicit),
546                ],
547                vec![arg("PROMPT", CoverageLevel::Explicit)],
548            ),
549            command(
550                &["review"],
551                CoverageLevel::Explicit,
552                None,
553                vec![
554                    flag("--base", CoverageLevel::Explicit),
555                    flag("--commit", CoverageLevel::Explicit),
556                    flag("--title", CoverageLevel::Explicit),
557                    flag("--uncommitted", CoverageLevel::Explicit),
558                ],
559                vec![arg("PROMPT", CoverageLevel::Explicit)],
560            ),
561            command(
562                &["resume"],
563                CoverageLevel::Explicit,
564                None,
565                vec![
566                    flag("--all", CoverageLevel::Explicit),
567                    flag("--last", CoverageLevel::Explicit),
568                ],
569                vec![
570                    arg("PROMPT", CoverageLevel::Explicit),
571                    arg("SESSION_ID", CoverageLevel::Explicit),
572                ],
573            ),
574            command(
575                &["fork"],
576                CoverageLevel::Explicit,
577                None,
578                vec![
579                    flag("--all", CoverageLevel::Explicit),
580                    flag("--last", CoverageLevel::Explicit),
581                ],
582                vec![
583                    arg("PROMPT", CoverageLevel::Explicit),
584                    arg("SESSION_ID", CoverageLevel::Explicit),
585                ],
586            ),
587            WrapperCommandCoverageV1 {
588                path: vec!["completion".to_string()],
589                level: CoverageLevel::IntentionallyUnsupported,
590                note: Some(
591                    "Shell completion generation is out of scope for the wrapper.".to_string(),
592                ),
593                scope: None,
594                flags: None,
595                args: Some(vec![arg_note(
596                    "SHELL",
597                    CoverageLevel::IntentionallyUnsupported,
598                    "Shell completion generation is out of scope for the wrapper.",
599                )]),
600            },
601        ],
602    }
603}