Skip to main content

forge/
introspect.rs

1//! Stable, agent-facing metadata for the `forge` command tree.
2//!
3//! See [`docs/agents/spec.md`](../../../docs/agents/spec.md). The registry
4//! pins `command_id`s and machine-mode capabilities for adopted commands.
5
6use foundry_cli::{
7    ExitCode,
8    introspect::{
9        Capabilities, CommandMeta, CommandRegistry, ExitCodeInfo, OutputMode, RegistryEntry,
10        SideEffects,
11    },
12};
13use std::borrow::Cow;
14
15/// Stable schema id for the `forge build` envelope payload.
16pub const BUILD_RESULT_SCHEMA: &str = "foundry:forge.build@v1";
17
18/// Stable schema id for `forge test` stream event records.
19pub const TEST_EVENT_SCHEMA: &str = "foundry:forge.test.event@v1";
20/// Stable schema id for the terminal `forge test` envelope payload.
21pub const TEST_RESULT_SCHEMA: &str = "foundry:forge.test@v1";
22
23/// Exit codes `forge build` may emit under `--machine`. Declared explicitly so
24/// agents don't have to assume "inherits global defaults"; codes not in this
25/// list are not produced by this command.
26static BUILD_EXIT_CODES: &[ExitCodeInfo] = &[
27    ExitCodeInfo {
28        code: ExitCode::Success.to_i32(),
29        name: Cow::Borrowed(ExitCode::Success.name()),
30        description: Cow::Borrowed("Build succeeded; envelope `success: true`."),
31    },
32    ExitCodeInfo {
33        code: ExitCode::GenericError.to_i32(),
34        name: Cow::Borrowed(ExitCode::GenericError.name()),
35        description: Cow::Borrowed(
36            "Unclassified failure outside the typed paths (envelope `cli.unknown`).",
37        ),
38    },
39    ExitCodeInfo {
40        code: ExitCode::Usage.to_i32(),
41        name: Cow::Borrowed(ExitCode::Usage.name()),
42        description: Cow::Borrowed(
43            "Flag combination rejected under `--machine` (envelope `cli.usage.invalid`).",
44        ),
45    },
46    ExitCodeInfo {
47        code: ExitCode::Build.to_i32(),
48        name: Cow::Borrowed(ExitCode::Build.name()),
49        description: Cow::Borrowed(
50            "Solc reported one or more compile errors (envelope `compiler.solc.error`).",
51        ),
52    },
53];
54
55/// Exit codes `forge test` may emit under `--machine`.
56static TEST_EXIT_CODES: &[ExitCodeInfo] = &[
57    ExitCodeInfo {
58        code: ExitCode::Success.to_i32(),
59        name: Cow::Borrowed(ExitCode::Success.name()),
60        description: Cow::Borrowed(
61            "All tests passed, or failures were tolerated by `--allow-failure`; envelope \
62             `success: true`. When `--allow-failure` is set, `data.failed` may be non-zero.",
63        ),
64    },
65    ExitCodeInfo {
66        code: ExitCode::GenericError.to_i32(),
67        name: Cow::Borrowed(ExitCode::GenericError.name()),
68        description: Cow::Borrowed(
69            "Unclassified failure outside the typed paths (envelope `cli.unknown`).",
70        ),
71    },
72    ExitCodeInfo {
73        code: ExitCode::Usage.to_i32(),
74        name: Cow::Borrowed(ExitCode::Usage.name()),
75        description: Cow::Borrowed(
76            "Flag combination rejected under `--machine` (envelope `cli.usage.invalid`).",
77        ),
78    },
79    ExitCodeInfo {
80        code: ExitCode::Build.to_i32(),
81        name: Cow::Borrowed(ExitCode::Build.name()),
82        description: Cow::Borrowed(
83            "Solc reported one or more compile errors before tests could run \
84             (envelope `compiler.solc.error`).",
85        ),
86    },
87    ExitCodeInfo {
88        code: ExitCode::TestFailure.to_i32(),
89        name: Cow::Borrowed(ExitCode::TestFailure.name()),
90        description: Cow::Borrowed(
91            "Test suite ran and at least one test failed without `--allow-failure` \
92             (envelope `test.failed`).",
93        ),
94    },
95];
96
97static ENTRIES: &[RegistryEntry] = &[
98    RegistryEntry {
99        path: &["build"],
100        meta: CommandMeta {
101            command_id: Some("forge.build"),
102            capabilities: Capabilities {
103                output_mode: OutputMode::Envelope,
104                result_schema_ref: Some(Cow::Borrowed(BUILD_RESULT_SCHEMA)),
105                event_schema_ref: None,
106                session_schema_ref: None,
107                reads_stdin: false,
108                supports_output_path: false,
109                requires_project: true,
110                side_effects: SideEffects::FsWrite,
111                long_running: false,
112                stateful: false,
113            },
114            capabilities_declared: true,
115            exit_codes: BUILD_EXIT_CODES,
116        },
117    },
118    RegistryEntry {
119        path: &["test"],
120        meta: CommandMeta {
121            command_id: Some("forge.test"),
122            capabilities: Capabilities {
123                output_mode: OutputMode::Stream,
124                result_schema_ref: Some(Cow::Borrowed(TEST_RESULT_SCHEMA)),
125                event_schema_ref: Some(Cow::Borrowed(TEST_EVENT_SCHEMA)),
126                session_schema_ref: None,
127                reads_stdin: false,
128                supports_output_path: false,
129                requires_project: true,
130                // `Network` subsumes the always-present `FsWrite`; `forge
131                // test` does not broadcast user txs, so not `ChainWrite`.
132                side_effects: SideEffects::Network,
133                long_running: true,
134                stateful: false,
135            },
136            capabilities_declared: true,
137            exit_codes: TEST_EXIT_CODES,
138        },
139    },
140];
141
142/// The `forge` command registry. Used by `--introspect` and by adoption code
143/// that needs to look up command metadata.
144pub const REGISTRY: CommandRegistry = CommandRegistry::new(ENTRIES);