1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//! Step 1 — command-line definition.
//!
//! clap handles CLI arguments and subcommands (`dev`, `export`, `build`, `check`, `init`).
use std::path::PathBuf;
use clap::builder::ValueHint;
use clap::{Parser, Subcommand};
/// Fusible — electronic linter & hardware-firmware bridge for tscircuit.
#[derive(Debug, Parser)]
#[command(
name = "fusible",
version,
about = "Electronic linter: the fuse blows to block firmware code generation",
after_help = "Examples:\n fusible --input circuit.json\n fusible check\n fusible dev"
)]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Commands>,
/// Path to the Circuit JSON or TSX file (shorthand for check)
#[arg(short = 'i', long, value_name = "FILE", value_hint = ValueHint::FilePath)]
pub input: Option<PathBuf>,
/// Silicon target, e.g. `stm32g431` (consumed by pin-muxing in phase 2)
#[arg(long, value_name = "MCU")]
pub mcu: Option<String>,
}
/// Available subcommands for managing tscircuit monorepo projects.
#[derive(Debug, Subcommand, PartialEq)]
pub enum Commands {
/// Start the interactive development server and web viewer
#[command(alias = "view", alias = "webview")]
Dev {
/// Entry file (.tsx, .json) or directory
#[arg(value_name = "FILE")]
file: Option<PathBuf>,
/// Port to run dev server on (default: 3020)
#[arg(short = 'p', long)]
port: Option<u16>,
/// Use legacy tsci dev server instead of native Fusible Studio
#[arg(long)]
legacy: bool,
},
/// Run the electronic linter on a circuit file or monorepo project
#[command(alias = "lint")]
Check {
/// Path to Circuit JSON, TSX, or KiCad entry file
#[arg(value_name = "FILE")]
file: Option<PathBuf>,
/// Silicon target, e.g. `stm32g431` or `esp32-s3`
#[arg(long, value_name = "MCU")]
mcu: Option<String>,
/// Destination path for generated firmware pin bindings (pins.rs)
#[arg(long, value_name = "PATH")]
pins_rs: Option<PathBuf>,
},
/// Compile circuit artifacts and build firmware
Build {
/// Path to entry TSX file
#[arg(value_name = "FILE")]
file: Option<PathBuf>,
},
/// Export tscircuit code to various formats (gerbers, svg, glb, etc.)
Export {
/// Path to entry TSX file
#[arg(value_name = "FILE")]
file: Option<PathBuf>,
/// Export preset batch: fab (gerbers + bom + pnp), cad (kicad + step), docs (svg + pdf), or all
#[arg(long, value_name = "PRESET")]
preset: Option<String>,
/// Output format (gerbers, pcb-svg, schematic-svg, glb, step, kicad_zip, etc.)
#[arg(short = 'f', long, default_value = "gerbers")]
format: String,
/// Output destination path or directory
#[arg(short = 'o', long)]
output: Option<PathBuf>,
/// Skip electrical rule verification before exporting
#[arg(long)]
skip_lint: bool,
},
/// Run the parallel autorouter to solve circuit traces
Route {
/// Path to Circuit JSON or TSX file
#[arg(value_name = "FILE")]
file: Option<PathBuf>,
/// Destination path for routed output
#[arg(short = 'o', long)]
output: Option<PathBuf>,
/// Clearance distance in millimeters
#[arg(long, default_value = "0.2")]
clearance: f64,
/// Trace width in millimeters
#[arg(long, default_value = "0.25")]
trace_width: f64,
/// Number of copper layers available for routing
#[arg(long, default_value = "2")]
layers: u8,
/// Validate routability without writing changes to disk
#[arg(long)]
dry_run: bool,
},
/// Compare PCB footprint placement between KiCad and tscircuit
Diff {
/// Path to KiCad PCB file (.kicad_pcb)
#[arg(value_name = "KICAD_PCB", required = true)]
kicad_pcb: PathBuf,
/// Path to Circuit JSON or TSX entry file
#[arg(value_name = "FILE")]
file: Option<PathBuf>,
},
/// Synchronize layout adjustments from KiCad back into tscircuit
Sync {
/// Path to KiCad PCB file (.kicad_pcb)
#[arg(value_name = "KICAD_PCB", required = true)]
kicad_pcb: PathBuf,
/// Path to Circuit JSON or TSX entry file
#[arg(value_name = "FILE")]
file: Option<PathBuf>,
/// Target manual-edits.json file path
#[arg(long, value_name = "TARGET")]
target: Option<PathBuf>,
/// Write layout changes to target file
#[arg(long)]
write: bool,
/// Run without modifying manual-edits.json
#[arg(long)]
dry_run: bool,
},
/// Initialize a new Fusible project and tscircuit hardware workspace
Init {
/// Target directory to initialize in (defaults to current directory)
#[arg(value_name = "PATH")]
path: Option<PathBuf>,
/// Optional project name
#[arg(long)]
name: Option<String>,
/// Target microcontroller (e.g. esp32-s3, stm32g431, rp2040)
#[arg(long)]
mcu: Option<String>,
/// Skip installing hardware npm/bun dependencies
#[arg(long)]
no_install: bool,
},
/// Add a tscircuit component or registry package to the hardware project
Add {
/// Packages to install (e.g. @tsci/seveibar.smd-resistor or @tscircuit/core)
#[arg(value_name = "PACKAGE", required = true)]
packages: Vec<String>,
},
/// Install all hardware dependencies in the project
Install {
/// Target directory (defaults to hardware/ or current directory)
#[arg(value_name = "DIR")]
dir: Option<PathBuf>,
},
/// Search the tscircuit registry for components, footprints, and CAD models
Search {
/// Search terms (e.g. "esp32", "usb-c", "resistor 0603")
#[arg(value_name = "QUERY", required = true)]
query: Vec<String>,
},
/// Inspect toolchain health and available tscircuit runners
#[command(alias = "setup")]
Doctor {
/// Automatically install tscircuit runner if missing
#[arg(long)]
install: bool,
},
}