@tscircuit/cli 0.1.1787 → 0.1.1788

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -80,6 +80,30 @@ The `build` command also accepts the following options:
80
80
  - `--ignore-placement-drc` - suppress placement DRC diagnostics
81
81
  - `--ignore-routing-drc` - suppress routing DRC diagnostics
82
82
 
83
+ ### Debug autorouting stages
84
+
85
+ Use `--autorouter-debug` to log each autorouting stage and write visual
86
+ artifacts while the circuit is being routed:
87
+
88
+ ```bash
89
+ tsci build index.circuit.tsx \
90
+ --autorouter-debug \
91
+ --autorouter-debug-dir dist/autorouter-debug \
92
+ --autorouter-dump-srj all
93
+ ```
94
+
95
+ The debug directory contains:
96
+
97
+ - `placement-unrouted.png` — PCB placement before routing starts.
98
+ - `phase-N-routed.png` — cumulative PCB routing after each zero-indexed stage.
99
+ A fanout router and its downstream router appear as separate stages.
100
+ - `phase-N.input.simple-route.json` and `phase-N.output.traces.json` when
101
+ `--autorouter-dump-srj all` is enabled.
102
+ - `board.meta.json` — phase timing and connection-count summary.
103
+
104
+ Use `--autorouter-dump-srj failed` to keep only failed-stage routing data, or
105
+ `--autorouter-dump-srj phase:N` to capture a single stage.
106
+
83
107
  ## Development
84
108
 
85
109
  This command will open the `index.tsx` file for editing.
@@ -12347,13 +12347,18 @@ class AutorouterDiagnostics {
12347
12347
  return filePath;
12348
12348
  }
12349
12349
  writePngSnapshot(fileName, circuitJson) {
12350
- const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
12351
- const png = convertSvgToPngBuffer(pcbSvg);
12352
- const debugDir = path2.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
12353
- fs2.mkdirSync(debugDir, { recursive: true });
12354
- const filePath = path2.join(debugDir, fileName);
12355
- fs2.writeFileSync(filePath, png);
12356
- this.logArtifact(filePath);
12350
+ try {
12351
+ const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
12352
+ const png = convertSvgToPngBuffer(pcbSvg);
12353
+ const debugDir = path2.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
12354
+ fs2.mkdirSync(debugDir, { recursive: true });
12355
+ const filePath = path2.join(debugDir, fileName);
12356
+ fs2.writeFileSync(filePath, png);
12357
+ this.logArtifact(filePath);
12358
+ } catch (error) {
12359
+ const serializedError = this.serializeError(error instanceof Error ? error : String(error));
12360
+ this.log(kleur_default.yellow(`Could not write autorouter debug image ${fileName}: ${serializedError.message}`));
12361
+ }
12357
12362
  }
12358
12363
  logArtifact(filePath) {
12359
12364
  this.log(`Wrote debug artifact: ${path2.relative(process.cwd(), filePath)}`);
@@ -12366,7 +12371,8 @@ class AutorouterDiagnostics {
12366
12371
  if (id)
12367
12372
  elementIndexById.set(id, index);
12368
12373
  }
12369
- for (const trace of this.completedPhaseTraces) {
12374
+ for (const autorouterTrace of this.completedPhaseTraces) {
12375
+ const trace = this.normalizeTraceForPcbSnapshot(autorouterTrace);
12370
12376
  if (!trace || typeof trace !== "object")
12371
12377
  continue;
12372
12378
  const id = this.getCircuitElementId(trace);
@@ -12381,6 +12387,23 @@ class AutorouterDiagnostics {
12381
12387
  }
12382
12388
  return circuitJson;
12383
12389
  }
12390
+ normalizeTraceForPcbSnapshot(trace) {
12391
+ return {
12392
+ ...trace,
12393
+ route: trace.route.map((point) => {
12394
+ if (point.route_type !== "through_obstacle")
12395
+ return point;
12396
+ return {
12397
+ route_type: "through_pad",
12398
+ start: point.start,
12399
+ end: point.end,
12400
+ start_layer: point.from_layer,
12401
+ end_layer: point.to_layer,
12402
+ width: point.width
12403
+ };
12404
+ })
12405
+ };
12406
+ }
12384
12407
  getCircuitElementId(element) {
12385
12408
  const idEntry = Object.entries(element).find(([key, value]) => key === `${element.type}_id` && typeof value === "string");
12386
12409
  const id = idEntry?.[1];
package/dist/cli/main.js CHANGED
@@ -123144,13 +123144,18 @@ class AutorouterDiagnostics {
123144
123144
  return filePath;
123145
123145
  }
123146
123146
  writePngSnapshot(fileName, circuitJson) {
123147
- const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
123148
- const png = convertSvgToPngBuffer(pcbSvg);
123149
- const debugDir = path17.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
123150
- fs17.mkdirSync(debugDir, { recursive: true });
123151
- const filePath = path17.join(debugDir, fileName);
123152
- fs17.writeFileSync(filePath, png);
123153
- this.logArtifact(filePath);
123147
+ try {
123148
+ const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
123149
+ const png = convertSvgToPngBuffer(pcbSvg);
123150
+ const debugDir = path17.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
123151
+ fs17.mkdirSync(debugDir, { recursive: true });
123152
+ const filePath = path17.join(debugDir, fileName);
123153
+ fs17.writeFileSync(filePath, png);
123154
+ this.logArtifact(filePath);
123155
+ } catch (error) {
123156
+ const serializedError = this.serializeError(error instanceof Error ? error : String(error));
123157
+ this.log(kleur_default.yellow(`Could not write autorouter debug image ${fileName}: ${serializedError.message}`));
123158
+ }
123154
123159
  }
123155
123160
  logArtifact(filePath) {
123156
123161
  this.log(`Wrote debug artifact: ${path17.relative(process.cwd(), filePath)}`);
@@ -123163,7 +123168,8 @@ class AutorouterDiagnostics {
123163
123168
  if (id)
123164
123169
  elementIndexById.set(id, index);
123165
123170
  }
123166
- for (const trace of this.completedPhaseTraces) {
123171
+ for (const autorouterTrace of this.completedPhaseTraces) {
123172
+ const trace = this.normalizeTraceForPcbSnapshot(autorouterTrace);
123167
123173
  if (!trace || typeof trace !== "object")
123168
123174
  continue;
123169
123175
  const id = this.getCircuitElementId(trace);
@@ -123178,6 +123184,23 @@ class AutorouterDiagnostics {
123178
123184
  }
123179
123185
  return circuitJson;
123180
123186
  }
123187
+ normalizeTraceForPcbSnapshot(trace) {
123188
+ return {
123189
+ ...trace,
123190
+ route: trace.route.map((point) => {
123191
+ if (point.route_type !== "through_obstacle")
123192
+ return point;
123193
+ return {
123194
+ route_type: "through_pad",
123195
+ start: point.start,
123196
+ end: point.end,
123197
+ start_layer: point.from_layer,
123198
+ end_layer: point.to_layer,
123199
+ width: point.width
123200
+ };
123201
+ })
123202
+ };
123203
+ }
123181
123204
  getCircuitElementId(element) {
123182
123205
  const idEntry = Object.entries(element).find(([key, value]) => key === `${element.type}_id` && typeof value === "string");
123183
123206
  const id = idEntry?.[1];
@@ -135250,7 +135273,7 @@ var parseInjectedProps = ({
135250
135273
  return parsed;
135251
135274
  };
135252
135275
  var registerBuild = (program2) => {
135253
- program2.command("build").description("Run tscircuit eval and output circuit json").argument("[file]", "Path to the entry file").option("--ci", "Run install and optional prebuild/build commands (or default CI build)").option("--ignore-errors", "Do not exit with code 1 on errors").option("--ignore-warnings", "Do not log warnings").option("--ignore-netlist-drc", "Ignore netlist DRC errors/warnings").option("--ignore-pin-specification-drc", "Ignore pin-specification DRC errors/warnings").option("--ignore-placement-drc", "Ignore placement DRC errors/warnings").option("--ignore-routing-drc", "Ignore routing DRC errors/warnings").option("--ignore-config", "Ignore options from tscircuit.config.json").option("--disable-pcb", "Disable PCB outputs").option("--routing-disabled", "Disable routing during circuit generation").option("--disable-parts-engine", "Disable the parts engine").option("--site", "Generate a static site in the dist directory").option("--transpile", "Transpile the entry file to JavaScript").option("--preview-images", "Generate preview images in the dist directory").option("--all-images", "Generate preview images for every successful build output").option("--pngs", "Generate PNG outputs during build generation").option("--pcb-png", "Generate PCB PNG outputs during build generation").option("--schematic-png", "Generate schematic PNG outputs during build generation").option("--svgs", "Generate SVG outputs during build generation").option("--pcb-svgs", "Generate PCB SVG outputs during build generation").option("--schematic-svgs", "Generate schematic SVG outputs during build generation").option("--simulation-svgs", "Generate simulation graph SVG outputs during build generation").option("--simulation-schematic-svgs", "Generate schematic simulation SVG outputs during build generation").option("--3d-png", "Generate 3D PNG outputs during build generation").option("--3d", "Generate 3D PNG outputs during build generation").option("--pcb-only", "Generate only PCB SVG outputs during build generation").option("--schematic-only", "Generate only schematic SVG outputs during build generation").option("--kicad-project", "Generate KiCad project directories for each successful build output").option("--kicad-project-zip", "Generate a zipped KiCad project for each successful build output").option("--kicad-library", "Generate KiCad library in dist/kicad-library").option("--kicad-library-name <name>", "Specify the name of the KiCad library").option("--preview-gltf", "Generate a GLTF file from the preview entrypoint").option("--show-courtyards", "Show courtyard outlines in PCB SVG outputs").option("--glbs", "Generate GLB 3D model files for every successful build").option("--step", "Generate STEP 3D model files for every successful build").option("--profile", "Log per-circuit circuit.json generation time during build").option("--autorouter-debug", "Log autorouting phase diagnostics during circuit generation").option("--autorouter-timeout <duration>", 'Abort an autorouting phase after a duration, e.g. "120s" or "2m"').option("--autorouter-debug-dir <path>", "Directory for autorouting debug artifacts (default: dist/autorouter-debug)").option("--autorouter-dump-srj [mode]", 'Dump SimpleRouteJson inputs/outputs: "all", "failed", or "phase:<index>" (default: failed)').option("--kicad-pcm", "Generate KiCad PCM (Plugin and Content Manager) assets in dist/pcm").option("--use-cdn-javascript", "Use CDN-hosted JavaScript instead of bundled standalone file for --site").option("--concurrency <number>", "Number of files to build in parallel (default: 1)", "1").option("--inject-props <json>", "Inject JSON props into the built file's default export").option("--inject-props-file <path>", "Inject JSON props from a file into the built file's default export").action(async (file, options) => {
135276
+ program2.command("build").description("Run tscircuit eval and output circuit json").argument("[file]", "Path to the entry file").option("--ci", "Run install and optional prebuild/build commands (or default CI build)").option("--ignore-errors", "Do not exit with code 1 on errors").option("--ignore-warnings", "Do not log warnings").option("--ignore-netlist-drc", "Ignore netlist DRC errors/warnings").option("--ignore-pin-specification-drc", "Ignore pin-specification DRC errors/warnings").option("--ignore-placement-drc", "Ignore placement DRC errors/warnings").option("--ignore-routing-drc", "Ignore routing DRC errors/warnings").option("--ignore-config", "Ignore options from tscircuit.config.json").option("--disable-pcb", "Disable PCB outputs").option("--routing-disabled", "Disable routing during circuit generation").option("--disable-parts-engine", "Disable the parts engine").option("--site", "Generate a static site in the dist directory").option("--transpile", "Transpile the entry file to JavaScript").option("--preview-images", "Generate preview images in the dist directory").option("--all-images", "Generate preview images for every successful build output").option("--pngs", "Generate PNG outputs during build generation").option("--pcb-png", "Generate PCB PNG outputs during build generation").option("--schematic-png", "Generate schematic PNG outputs during build generation").option("--svgs", "Generate SVG outputs during build generation").option("--pcb-svgs", "Generate PCB SVG outputs during build generation").option("--schematic-svgs", "Generate schematic SVG outputs during build generation").option("--simulation-svgs", "Generate simulation graph SVG outputs during build generation").option("--simulation-schematic-svgs", "Generate schematic simulation SVG outputs during build generation").option("--3d-png", "Generate 3D PNG outputs during build generation").option("--3d", "Generate 3D PNG outputs during build generation").option("--pcb-only", "Generate only PCB SVG outputs during build generation").option("--schematic-only", "Generate only schematic SVG outputs during build generation").option("--kicad-project", "Generate KiCad project directories for each successful build output").option("--kicad-project-zip", "Generate a zipped KiCad project for each successful build output").option("--kicad-library", "Generate KiCad library in dist/kicad-library").option("--kicad-library-name <name>", "Specify the name of the KiCad library").option("--preview-gltf", "Generate a GLTF file from the preview entrypoint").option("--show-courtyards", "Show courtyard outlines in PCB SVG outputs").option("--glbs", "Generate GLB 3D model files for every successful build").option("--step", "Generate STEP 3D model files for every successful build").option("--profile", "Log per-circuit circuit.json generation time during build").option("--autorouter-debug", "Log autorouting phases and write unrouted/per-phase PNG artifacts").option("--autorouter-timeout <duration>", 'Abort an autorouting phase after a duration, e.g. "120s" or "2m"').option("--autorouter-debug-dir <path>", "Directory for autorouting debug artifacts (default: dist/autorouter-debug)").option("--autorouter-dump-srj [mode]", 'Dump SimpleRouteJson inputs/outputs: "all", "failed", or "phase:<index>" (default: failed)').option("--kicad-pcm", "Generate KiCad PCM (Plugin and Content Manager) assets in dist/pcm").option("--use-cdn-javascript", "Use CDN-hosted JavaScript instead of bundled standalone file for --site").option("--concurrency <number>", "Number of files to build in parallel (default: 1)", "1").option("--inject-props <json>", "Inject JSON props into the built file's default export").option("--inject-props-file <path>", "Inject JSON props from a file into the built file's default export").action(async (file, options) => {
135254
135277
  try {
135255
135278
  const transpileExplicitlyRequested = options?.transpile === true;
135256
135279
  const resolvedRoot = path44.resolve(process.cwd());
@@ -284937,7 +284960,7 @@ var checkTraceLength = async (pinOrNetRef, file, options = {}) => {
284937
284960
  return analysis.toString();
284938
284961
  };
284939
284962
  var registerCheckTraceLength = (program2) => {
284940
- program2.commands.find((c3) => c3.name() === "check").command("trace-length").description("Analyze trace length for a pin or net").argument("<pinOrNetRef>", "Pin or net target to analyze").argument("[file]", "Path to the entry file").option("--autorouter-debug", "Log autorouting phase diagnostics during circuit generation").option("--autorouter-timeout <duration>", 'Abort an autorouting phase after a duration, e.g. "120s" or "2m"').option("--autorouter-debug-dir <path>", "Directory for autorouting debug artifacts (default: dist/autorouter-debug)").option("--autorouter-dump-srj [mode]", 'Dump SimpleRouteJson inputs/outputs: "all", "failed", or "phase:<index>" (default: failed)').action(async (pinOrNetRef, file, options) => {
284963
+ program2.commands.find((c3) => c3.name() === "check").command("trace-length").description("Analyze trace length for a pin or net").argument("<pinOrNetRef>", "Pin or net target to analyze").argument("[file]", "Path to the entry file").option("--autorouter-debug", "Log autorouting phases and write unrouted/per-phase PNG artifacts").option("--autorouter-timeout <duration>", 'Abort an autorouting phase after a duration, e.g. "120s" or "2m"').option("--autorouter-debug-dir <path>", "Directory for autorouting debug artifacts (default: dist/autorouter-debug)").option("--autorouter-dump-srj [mode]", 'Dump SimpleRouteJson inputs/outputs: "all", "failed", or "phase:<index>" (default: failed)').action(async (pinOrNetRef, file, options) => {
284941
284964
  try {
284942
284965
  const output = await checkTraceLength(pinOrNetRef, file, options);
284943
284966
  console.log(output);
@@ -3300,13 +3300,18 @@ class AutorouterDiagnostics {
3300
3300
  return filePath;
3301
3301
  }
3302
3302
  writePngSnapshot(fileName, circuitJson) {
3303
- const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
3304
- const png = convertSvgToPngBuffer(pcbSvg);
3305
- const debugDir = path2.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
3306
- fs2.mkdirSync(debugDir, { recursive: true });
3307
- const filePath = path2.join(debugDir, fileName);
3308
- fs2.writeFileSync(filePath, png);
3309
- this.logArtifact(filePath);
3303
+ try {
3304
+ const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
3305
+ const png = convertSvgToPngBuffer(pcbSvg);
3306
+ const debugDir = path2.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
3307
+ fs2.mkdirSync(debugDir, { recursive: true });
3308
+ const filePath = path2.join(debugDir, fileName);
3309
+ fs2.writeFileSync(filePath, png);
3310
+ this.logArtifact(filePath);
3311
+ } catch (error) {
3312
+ const serializedError = this.serializeError(error instanceof Error ? error : String(error));
3313
+ this.log(kleur_default.yellow(`Could not write autorouter debug image ${fileName}: ${serializedError.message}`));
3314
+ }
3310
3315
  }
3311
3316
  logArtifact(filePath) {
3312
3317
  this.log(`Wrote debug artifact: ${path2.relative(process.cwd(), filePath)}`);
@@ -3319,7 +3324,8 @@ class AutorouterDiagnostics {
3319
3324
  if (id)
3320
3325
  elementIndexById.set(id, index);
3321
3326
  }
3322
- for (const trace of this.completedPhaseTraces) {
3327
+ for (const autorouterTrace of this.completedPhaseTraces) {
3328
+ const trace = this.normalizeTraceForPcbSnapshot(autorouterTrace);
3323
3329
  if (!trace || typeof trace !== "object")
3324
3330
  continue;
3325
3331
  const id = this.getCircuitElementId(trace);
@@ -3334,6 +3340,23 @@ class AutorouterDiagnostics {
3334
3340
  }
3335
3341
  return circuitJson;
3336
3342
  }
3343
+ normalizeTraceForPcbSnapshot(trace) {
3344
+ return {
3345
+ ...trace,
3346
+ route: trace.route.map((point) => {
3347
+ if (point.route_type !== "through_obstacle")
3348
+ return point;
3349
+ return {
3350
+ route_type: "through_pad",
3351
+ start: point.start,
3352
+ end: point.end,
3353
+ start_layer: point.from_layer,
3354
+ end_layer: point.to_layer,
3355
+ width: point.width
3356
+ };
3357
+ })
3358
+ };
3359
+ }
3337
3360
  getCircuitElementId(element) {
3338
3361
  const idEntry = Object.entries(element).find(([key, value]) => key === `${element.type}_id` && typeof value === "string");
3339
3362
  const id = idEntry?.[1];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.1787",
3
+ "version": "0.1.1788",
4
4
  "main": "dist/cli/main.js",
5
5
  "exports": {
6
6
  ".": "./dist/cli/main.js",