@tscircuit/cli 0.1.1631 → 0.1.1632

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.
@@ -5608,8 +5608,8 @@ var require_utils = __commonJS((exports, module) => {
5608
5608
  }
5609
5609
  return ind;
5610
5610
  }
5611
- function removeDotSegments(path10) {
5612
- let input = path10;
5611
+ function removeDotSegments(path11) {
5612
+ let input = path11;
5613
5613
  const output = [];
5614
5614
  let nextSlash = -1;
5615
5615
  let len = 0;
@@ -5852,8 +5852,8 @@ var require_schemes = __commonJS((exports, module) => {
5852
5852
  wsComponent.secure = undefined;
5853
5853
  }
5854
5854
  if (wsComponent.resourceName) {
5855
- const [path10, query] = wsComponent.resourceName.split("?");
5856
- wsComponent.path = path10 && path10 !== "/" ? path10 : undefined;
5855
+ const [path11, query] = wsComponent.resourceName.split("?");
5856
+ wsComponent.path = path11 && path11 !== "/" ? path11 : undefined;
5857
5857
  wsComponent.query = query;
5858
5858
  wsComponent.resourceName = undefined;
5859
5859
  }
@@ -11883,6 +11883,7 @@ var import_make_vfs = __toESM(require_dist(), 1);
11883
11883
  // lib/shared/autorouter-diagnostics.ts
11884
11884
  import fs2 from "node:fs";
11885
11885
  import path2 from "node:path";
11886
+ import { convertCircuitJsonToPcbSvg } from "circuit-to-svg";
11886
11887
 
11887
11888
  // node_modules/kleur/index.mjs
11888
11889
  var FORCE_COLOR;
@@ -11981,6 +11982,17 @@ function init(open, close) {
11981
11982
  }
11982
11983
  var kleur_default = $;
11983
11984
 
11985
+ // lib/shared/convert-svg-to-png.ts
11986
+ import { Resvg } from "@resvg/resvg-js";
11987
+ var convertSvgToPngBuffer = (svg) => {
11988
+ const resvg = new Resvg(svg, {
11989
+ fitTo: {
11990
+ mode: "original"
11991
+ }
11992
+ });
11993
+ return resvg.render().asPng();
11994
+ };
11995
+
11984
11996
  // lib/shared/autorouter-diagnostics.ts
11985
11997
  var DEFAULT_DEBUG_DIR = path2.join("dist", "autorouter-debug");
11986
11998
  var PROGRESS_LOG_INTERVAL_MS = 1e4;
@@ -12028,6 +12040,7 @@ class AutorouterDiagnostics {
12028
12040
  traceCountBySubcircuit = new Map;
12029
12041
  activePhase = null;
12030
12042
  completedPhaseTraces = [];
12043
+ hasWrittenPlacementSnapshot = false;
12031
12044
  summary = [];
12032
12045
  rootCircuit;
12033
12046
  constructor(options = {}) {
@@ -12060,7 +12073,6 @@ class AutorouterDiagnostics {
12060
12073
  const phaseLabel = this.getPhaseLabel(this.activePhase);
12061
12074
  const message = `Autorouter timeout after ${this.formatElapsed(elapsedMs)} in ${phaseLabel}.`;
12062
12075
  this.log(kleur_default.red(message));
12063
- this.log(`Wrote debug artifact: ${path2.relative(process.cwd(), artifactPath)}`);
12064
12076
  throw new AutorouterPhaseTimeoutError(message, artifactPath);
12065
12077
  }
12066
12078
  finalize(circuitJson) {
@@ -12102,6 +12114,11 @@ class AutorouterDiagnostics {
12102
12114
  hasLoggedStart: false,
12103
12115
  longRunningLoggingStarted: false
12104
12116
  };
12117
+ if (this.options.enabled && !this.hasWrittenPlacementSnapshot) {
12118
+ const placementCircuitJson = this.getCurrentCircuitJson().filter((element) => !this.isRouteElement(element));
12119
+ this.writePngSnapshot("placement-unrouted.png", placementCircuitJson);
12120
+ this.hasWrittenPlacementSnapshot = true;
12121
+ }
12105
12122
  if (this.options.enabled) {
12106
12123
  this.logPhaseStart(this.activePhase);
12107
12124
  }
@@ -12164,6 +12181,9 @@ class AutorouterDiagnostics {
12164
12181
  if (this.shouldDumpSuccessfulOutput(activePhase.routingPhaseIndex)) {
12165
12182
  this.writeJson(this.getPhaseFileName(activePhase, "output.traces.json"), outputSrj?.traces ?? []);
12166
12183
  }
12184
+ if (this.options.enabled) {
12185
+ this.writePngSnapshot(`phase-${activePhase.routingPhaseIndex}-routed.png`, this.getCircuitJsonWithCompletedPhaseTraces());
12186
+ }
12167
12187
  if (this.activePhase === activePhase) {
12168
12188
  this.activePhase = null;
12169
12189
  }
@@ -12323,8 +12343,54 @@ class AutorouterDiagnostics {
12323
12343
  fs2.mkdirSync(debugDir, { recursive: true });
12324
12344
  const filePath = path2.join(debugDir, fileName);
12325
12345
  fs2.writeFileSync(filePath, JSON.stringify(value, null, 2));
12346
+ this.logArtifact(filePath);
12326
12347
  return filePath;
12327
12348
  }
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);
12357
+ }
12358
+ logArtifact(filePath) {
12359
+ this.log(`Wrote debug artifact: ${path2.relative(process.cwd(), filePath)}`);
12360
+ }
12361
+ getCircuitJsonWithCompletedPhaseTraces() {
12362
+ const circuitJson = [...this.getCurrentCircuitJson()];
12363
+ const elementIndexById = new Map;
12364
+ for (const [index, element] of circuitJson.entries()) {
12365
+ const id = this.getCircuitElementId(element);
12366
+ if (id)
12367
+ elementIndexById.set(id, index);
12368
+ }
12369
+ for (const trace of this.completedPhaseTraces) {
12370
+ if (!trace || typeof trace !== "object")
12371
+ continue;
12372
+ const element = trace;
12373
+ const id = this.getCircuitElementId(element);
12374
+ const existingIndex = id ? elementIndexById.get(id) : undefined;
12375
+ if (existingIndex === undefined) {
12376
+ circuitJson.push(element);
12377
+ if (id)
12378
+ elementIndexById.set(id, circuitJson.length - 1);
12379
+ } else {
12380
+ circuitJson[existingIndex] = element;
12381
+ }
12382
+ }
12383
+ return circuitJson;
12384
+ }
12385
+ getCircuitElementId(element) {
12386
+ if (typeof element.type !== "string")
12387
+ return;
12388
+ const id = element[`${element.type}_id`];
12389
+ return typeof id === "string" ? id : undefined;
12390
+ }
12391
+ isRouteElement(element) {
12392
+ return element.type === "pcb_trace" || element.type === "pcb_via";
12393
+ }
12328
12394
  getPhaseFileName(activePhase, suffix) {
12329
12395
  const phaseNumber = activePhase.routingPhaseIndex;
12330
12396
  return `phase-${phaseNumber}.${suffix}`;
@@ -12655,7 +12721,7 @@ async function generateCircuitJson({
12655
12721
  }
12656
12722
  runner.emit("renderComplete");
12657
12723
  const circuitJson = await runner.getCircuitJson();
12658
- autorouterDiagnostics.finalize(circuitJson);
12724
+ await autorouterDiagnostics.finalize(circuitJson);
12659
12725
  if (saveToFile) {
12660
12726
  debug(`Saving circuit JSON to ${outputPath}`);
12661
12727
  fs5.writeFileSync(outputPath, JSON.stringify(circuitJson, null, 2));
@@ -13126,6 +13192,9 @@ var renderCircuitJsonTo3dPng = async (circuitJson, options = {}) => {
13126
13192
  return renderGLTFToPNGFromGLB(glbArrayBuffer, getRenderCamera(circuitJson, defaultCamera, options));
13127
13193
  };
13128
13194
 
13195
+ // cli/build/worker-output-generators.ts
13196
+ import { convertCircuitJsonToGltf } from "circuit-json-to-gltf";
13197
+
13129
13198
  // node_modules/circuit-json-to-step/node_modules/stepts/dist/index.js
13130
13199
  var Entity = class {
13131
13200
  static parse(_a, _ctx) {
@@ -15412,17 +15481,78 @@ async function circuitJsonToStep(circuitJson, options = {}) {
15412
15481
  }
15413
15482
 
15414
15483
  // cli/build/worker-output-generators.ts
15415
- import { convertCircuitJsonToGltf } from "circuit-json-to-gltf";
15416
15484
  import {
15417
- convertCircuitJsonToPcbSvg,
15485
+ convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg2,
15418
15486
  convertCircuitJsonToSchematicSvg
15419
15487
  } from "circuit-to-svg";
15420
15488
 
15489
+ // lib/shared/load-local-step-model-fs-map.ts
15490
+ import { existsSync as existsSync2 } from "node:fs";
15491
+ import { readFile } from "node:fs/promises";
15492
+ import path7 from "node:path";
15493
+ var isRemoteUrl = (value) => /^https?:\/\//i.test(value);
15494
+ async function loadLocalStepModelFsMap(circuitJson) {
15495
+ const fsMap = {};
15496
+ for (const element of circuitJson) {
15497
+ if (!element || typeof element !== "object")
15498
+ continue;
15499
+ const modelUrl = element.model_step_url;
15500
+ if (typeof modelUrl !== "string" || modelUrl.length === 0)
15501
+ continue;
15502
+ if (isRemoteUrl(modelUrl) || fsMap[modelUrl])
15503
+ continue;
15504
+ const localPath = path7.resolve(process.cwd(), modelUrl);
15505
+ if (!existsSync2(localPath))
15506
+ continue;
15507
+ fsMap[modelUrl] = await readFile(localPath, "utf-8");
15508
+ }
15509
+ return fsMap;
15510
+ }
15511
+
15512
+ // lib/shared/simulation-svg-assets.ts
15513
+ import {
15514
+ convertCircuitJsonToSchematicSimulationSvg,
15515
+ convertCircuitJsonToSimulationGraphSvg,
15516
+ isSimulationExperiment,
15517
+ isSimulationTransientVoltageGraph
15518
+ } from "circuit-to-svg";
15519
+ var isSimulationTransientCurrentGraph = (element) => element.type === "simulation_transient_current_graph";
15520
+ var getSimulationSvgInputs = (circuitJson) => {
15521
+ const simulationExperiment = circuitJson.find(isSimulationExperiment);
15522
+ if (!simulationExperiment)
15523
+ return;
15524
+ const simulationTransientCurrentGraphIds = circuitJson.filter((element) => isSimulationTransientCurrentGraph(element) && element.simulation_experiment_id === simulationExperiment.simulation_experiment_id).map((element) => element.simulation_transient_current_graph_id);
15525
+ const simulationTransientVoltageGraphIds = circuitJson.filter((element) => isSimulationTransientVoltageGraph(element) && element.simulation_experiment_id === simulationExperiment.simulation_experiment_id).map((element) => element.simulation_transient_voltage_graph_id);
15526
+ if (simulationTransientCurrentGraphIds.length === 0 && simulationTransientVoltageGraphIds.length === 0) {
15527
+ return;
15528
+ }
15529
+ return {
15530
+ simulation_experiment_id: simulationExperiment.simulation_experiment_id,
15531
+ simulation_transient_current_graph_ids: simulationTransientCurrentGraphIds,
15532
+ simulation_transient_voltage_graph_ids: simulationTransientVoltageGraphIds
15533
+ };
15534
+ };
15535
+ var getSimulationSvgAssetsFromCircuitJson = (circuitJson) => {
15536
+ const simulationSvgInputs = getSimulationSvgInputs(circuitJson);
15537
+ if (!simulationSvgInputs)
15538
+ return;
15539
+ return {
15540
+ simulationSvg: convertCircuitJsonToSimulationGraphSvg({
15541
+ circuitJson,
15542
+ ...simulationSvgInputs
15543
+ }),
15544
+ schematicSimulationSvg: convertCircuitJsonToSchematicSimulationSvg({
15545
+ circuitJson,
15546
+ ...simulationSvgInputs
15547
+ })
15548
+ };
15549
+ };
15550
+
15421
15551
  // node_modules/conf/dist/source/index.js
15422
15552
  import { isDeepStrictEqual } from "node:util";
15423
15553
  import process7 from "node:process";
15424
15554
  import fs8 from "node:fs";
15425
- import path10 from "node:path";
15555
+ import path11 from "node:path";
15426
15556
  import crypto from "node:crypto";
15427
15557
  import assert from "node:assert";
15428
15558
 
@@ -15437,12 +15567,12 @@ var disallowedKeys = new Set([
15437
15567
  "constructor"
15438
15568
  ]);
15439
15569
  var digits = new Set("0123456789");
15440
- function getPathSegments(path7) {
15570
+ function getPathSegments(path8) {
15441
15571
  const parts = [];
15442
15572
  let currentSegment = "";
15443
15573
  let currentPart = "start";
15444
15574
  let isIgnoring = false;
15445
- for (const character of path7) {
15575
+ for (const character of path8) {
15446
15576
  switch (character) {
15447
15577
  case "\\": {
15448
15578
  if (currentPart === "index") {
@@ -15564,11 +15694,11 @@ function assertNotStringIndex(object, key) {
15564
15694
  throw new Error("Cannot use string index");
15565
15695
  }
15566
15696
  }
15567
- function getProperty(object, path7, value) {
15568
- if (!isObject(object) || typeof path7 !== "string") {
15697
+ function getProperty(object, path8, value) {
15698
+ if (!isObject(object) || typeof path8 !== "string") {
15569
15699
  return value === undefined ? object : value;
15570
15700
  }
15571
- const pathArray = getPathSegments(path7);
15701
+ const pathArray = getPathSegments(path8);
15572
15702
  if (pathArray.length === 0) {
15573
15703
  return value;
15574
15704
  }
@@ -15588,12 +15718,12 @@ function getProperty(object, path7, value) {
15588
15718
  }
15589
15719
  return object === undefined ? value : object;
15590
15720
  }
15591
- function setProperty(object, path7, value) {
15592
- if (!isObject(object) || typeof path7 !== "string") {
15721
+ function setProperty(object, path8, value) {
15722
+ if (!isObject(object) || typeof path8 !== "string") {
15593
15723
  return object;
15594
15724
  }
15595
15725
  const root = object;
15596
- const pathArray = getPathSegments(path7);
15726
+ const pathArray = getPathSegments(path8);
15597
15727
  for (let index = 0;index < pathArray.length; index++) {
15598
15728
  const key = pathArray[index];
15599
15729
  assertNotStringIndex(object, key);
@@ -15606,11 +15736,11 @@ function setProperty(object, path7, value) {
15606
15736
  }
15607
15737
  return root;
15608
15738
  }
15609
- function deleteProperty(object, path7) {
15610
- if (!isObject(object) || typeof path7 !== "string") {
15739
+ function deleteProperty(object, path8) {
15740
+ if (!isObject(object) || typeof path8 !== "string") {
15611
15741
  return false;
15612
15742
  }
15613
- const pathArray = getPathSegments(path7);
15743
+ const pathArray = getPathSegments(path8);
15614
15744
  for (let index = 0;index < pathArray.length; index++) {
15615
15745
  const key = pathArray[index];
15616
15746
  assertNotStringIndex(object, key);
@@ -15624,11 +15754,11 @@ function deleteProperty(object, path7) {
15624
15754
  }
15625
15755
  }
15626
15756
  }
15627
- function hasProperty(object, path7) {
15628
- if (!isObject(object) || typeof path7 !== "string") {
15757
+ function hasProperty(object, path8) {
15758
+ if (!isObject(object) || typeof path8 !== "string") {
15629
15759
  return false;
15630
15760
  }
15631
- const pathArray = getPathSegments(path7);
15761
+ const pathArray = getPathSegments(path8);
15632
15762
  if (pathArray.length === 0) {
15633
15763
  return false;
15634
15764
  }
@@ -15642,41 +15772,41 @@ function hasProperty(object, path7) {
15642
15772
  }
15643
15773
 
15644
15774
  // node_modules/env-paths/index.js
15645
- import path7 from "node:path";
15775
+ import path8 from "node:path";
15646
15776
  import os from "node:os";
15647
15777
  import process2 from "node:process";
15648
15778
  var homedir = os.homedir();
15649
15779
  var tmpdir = os.tmpdir();
15650
15780
  var { env } = process2;
15651
15781
  var macos = (name) => {
15652
- const library = path7.join(homedir, "Library");
15782
+ const library = path8.join(homedir, "Library");
15653
15783
  return {
15654
- data: path7.join(library, "Application Support", name),
15655
- config: path7.join(library, "Preferences", name),
15656
- cache: path7.join(library, "Caches", name),
15657
- log: path7.join(library, "Logs", name),
15658
- temp: path7.join(tmpdir, name)
15784
+ data: path8.join(library, "Application Support", name),
15785
+ config: path8.join(library, "Preferences", name),
15786
+ cache: path8.join(library, "Caches", name),
15787
+ log: path8.join(library, "Logs", name),
15788
+ temp: path8.join(tmpdir, name)
15659
15789
  };
15660
15790
  };
15661
15791
  var windows = (name) => {
15662
- const appData = env.APPDATA || path7.join(homedir, "AppData", "Roaming");
15663
- const localAppData = env.LOCALAPPDATA || path7.join(homedir, "AppData", "Local");
15792
+ const appData = env.APPDATA || path8.join(homedir, "AppData", "Roaming");
15793
+ const localAppData = env.LOCALAPPDATA || path8.join(homedir, "AppData", "Local");
15664
15794
  return {
15665
- data: path7.join(localAppData, name, "Data"),
15666
- config: path7.join(appData, name, "Config"),
15667
- cache: path7.join(localAppData, name, "Cache"),
15668
- log: path7.join(localAppData, name, "Log"),
15669
- temp: path7.join(tmpdir, name)
15795
+ data: path8.join(localAppData, name, "Data"),
15796
+ config: path8.join(appData, name, "Config"),
15797
+ cache: path8.join(localAppData, name, "Cache"),
15798
+ log: path8.join(localAppData, name, "Log"),
15799
+ temp: path8.join(tmpdir, name)
15670
15800
  };
15671
15801
  };
15672
15802
  var linux = (name) => {
15673
- const username = path7.basename(homedir);
15803
+ const username = path8.basename(homedir);
15674
15804
  return {
15675
- data: path7.join(env.XDG_DATA_HOME || path7.join(homedir, ".local", "share"), name),
15676
- config: path7.join(env.XDG_CONFIG_HOME || path7.join(homedir, ".config"), name),
15677
- cache: path7.join(env.XDG_CACHE_HOME || path7.join(homedir, ".cache"), name),
15678
- log: path7.join(env.XDG_STATE_HOME || path7.join(homedir, ".local", "state"), name),
15679
- temp: path7.join(tmpdir, username, name)
15805
+ data: path8.join(env.XDG_DATA_HOME || path8.join(homedir, ".local", "share"), name),
15806
+ config: path8.join(env.XDG_CONFIG_HOME || path8.join(homedir, ".config"), name),
15807
+ cache: path8.join(env.XDG_CACHE_HOME || path8.join(homedir, ".cache"), name),
15808
+ log: path8.join(env.XDG_STATE_HOME || path8.join(homedir, ".local", "state"), name),
15809
+ temp: path8.join(tmpdir, username, name)
15680
15810
  };
15681
15811
  };
15682
15812
  function envPaths(name, { suffix = "nodejs" } = {}) {
@@ -15696,7 +15826,7 @@ function envPaths(name, { suffix = "nodejs" } = {}) {
15696
15826
  }
15697
15827
 
15698
15828
  // node_modules/atomically/dist/index.js
15699
- import path9 from "node:path";
15829
+ import path10 from "node:path";
15700
15830
 
15701
15831
  // node_modules/stubborn-fs/dist/index.js
15702
15832
  import fs7 from "node:fs";
@@ -15893,7 +16023,7 @@ var isUndefined = (value) => {
15893
16023
  };
15894
16024
 
15895
16025
  // node_modules/atomically/dist/utils/temp.js
15896
- import path8 from "node:path";
16026
+ import path9 from "node:path";
15897
16027
 
15898
16028
  // node_modules/when-exit/dist/node/interceptor.js
15899
16029
  import process6 from "node:process";
@@ -15993,7 +16123,7 @@ var Temp = {
15993
16123
  }
15994
16124
  },
15995
16125
  truncate: (filePath) => {
15996
- const basename = path8.basename(filePath);
16126
+ const basename = path9.basename(filePath);
15997
16127
  if (basename.length <= LIMIT_BASENAME_LENGTH)
15998
16128
  return filePath;
15999
16129
  const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename);
@@ -16035,7 +16165,7 @@ function writeFileSync2(filePath, data, options = DEFAULT_WRITE_OPTIONS) {
16035
16165
  }
16036
16166
  }
16037
16167
  if (!filePathExists) {
16038
- const parentPath = path9.dirname(filePath);
16168
+ const parentPath = path10.dirname(filePath);
16039
16169
  dist_default.attempt.mkdirSync(parentPath, {
16040
16170
  mode: DEFAULT_FOLDER_MODE,
16041
16171
  recursive: true
@@ -16351,7 +16481,7 @@ class Conf {
16351
16481
  this.events = new EventTarget;
16352
16482
  this.#encryptionKey = options.encryptionKey;
16353
16483
  const fileExtension = options.fileExtension ? `.${options.fileExtension}` : "";
16354
- this.path = path10.resolve(options.cwd, `${options.configName ?? "config"}${fileExtension}`);
16484
+ this.path = path11.resolve(options.cwd, `${options.configName ?? "config"}${fileExtension}`);
16355
16485
  const fileStore = this.store;
16356
16486
  const store = Object.assign(createPlainObject(), options.defaults, fileStore);
16357
16487
  if (options.migrations) {
@@ -16525,7 +16655,7 @@ class Conf {
16525
16655
  throw new Error("Config schema violation: " + errors.join("; "));
16526
16656
  }
16527
16657
  _ensureDirectory() {
16528
- fs8.mkdirSync(path10.dirname(this.path), { recursive: true });
16658
+ fs8.mkdirSync(path11.dirname(this.path), { recursive: true });
16529
16659
  }
16530
16660
  _write(value) {
16531
16661
  let data = this._serialize(value);
@@ -16697,12 +16827,12 @@ function jwtDecode(token, options) {
16697
16827
  // lib/cli-config/index.ts
16698
16828
  import fs10 from "node:fs";
16699
16829
  import os3 from "node:os";
16700
- import path12 from "node:path";
16830
+ import path13 from "node:path";
16701
16831
 
16702
16832
  // lib/shared/handle-registry-auth-error.ts
16703
16833
  import fs9 from "node:fs";
16704
16834
  import os2 from "node:os";
16705
- import path11 from "node:path";
16835
+ import path12 from "node:path";
16706
16836
  var AUTH_TOKEN_REGEX = /^\/\/npm\.tscircuit\.com\/:_authToken=(.+)$/m;
16707
16837
  function isUnauthorizedError(error) {
16708
16838
  const output = [
@@ -16735,8 +16865,8 @@ function handleRegistryAuthError({
16735
16865
  if (!isUnauthorizedError(error))
16736
16866
  return;
16737
16867
  const npmrcPaths = [
16738
- path11.join(projectDir, ".npmrc"),
16739
- path11.join(os2.homedir(), ".npmrc")
16868
+ path12.join(projectDir, ".npmrc"),
16869
+ path12.join(os2.homedir(), ".npmrc")
16740
16870
  ];
16741
16871
  const hasToken = npmrcPaths.some(hasTsciAuthToken);
16742
16872
  if (hasToken) {
@@ -16759,8 +16889,8 @@ var getSessionToken = () => {
16759
16889
  };
16760
16890
  var getSessionTokenFromNpmrc = () => {
16761
16891
  const npmrcPaths = [
16762
- path12.join(process.cwd(), ".npmrc"),
16763
- path12.join(os3.homedir(), ".npmrc")
16892
+ path13.join(process.cwd(), ".npmrc"),
16893
+ path13.join(os3.homedir(), ".npmrc")
16764
16894
  ];
16765
16895
  for (const npmrcPath of npmrcPaths) {
16766
16896
  if (!fs10.existsSync(npmrcPath))
@@ -16803,7 +16933,7 @@ var getCircuitJsonToGltfOptions = ({
16803
16933
  };
16804
16934
 
16805
16935
  // cli/build/convert-model-urls-to-file-urls.ts
16806
- import path13 from "node:path";
16936
+ import path14 from "node:path";
16807
16937
  import { pathToFileURL as pathToFileURL3 } from "node:url";
16808
16938
  var convertModelUrlsToFileUrls = (circuitJson) => {
16809
16939
  const modelUrlKeys2 = [
@@ -16830,7 +16960,7 @@ var convertModelUrlsToFileUrls = (circuitJson) => {
16830
16960
  if (value.startsWith("/") || value.match(/^[a-zA-Z]:\\/)) {
16831
16961
  updated[key] = pathToFileURL3(value).href;
16832
16962
  } else if (value.startsWith(".")) {
16833
- updated[key] = pathToFileURL3(path13.resolve(process.cwd(), value)).href;
16963
+ updated[key] = pathToFileURL3(path14.resolve(process.cwd(), value)).href;
16834
16964
  }
16835
16965
  }
16836
16966
  }
@@ -16857,79 +16987,6 @@ var normalizeToUint8Array2 = (value) => {
16857
16987
  throw new Error("Expected Uint8Array, ArrayBuffer, or ArrayBufferView for binary data");
16858
16988
  };
16859
16989
 
16860
- // cli/build/svg-to-png.ts
16861
- import { Resvg } from "@resvg/resvg-js";
16862
- var convertSvgToPngBuffer = async (svg) => {
16863
- const resvg = new Resvg(svg, {
16864
- fitTo: {
16865
- mode: "original"
16866
- }
16867
- });
16868
- return resvg.render().asPng();
16869
- };
16870
-
16871
- // lib/shared/load-local-step-model-fs-map.ts
16872
- import { existsSync as existsSync2 } from "node:fs";
16873
- import { readFile } from "node:fs/promises";
16874
- import path14 from "node:path";
16875
- var isRemoteUrl = (value) => /^https?:\/\//i.test(value);
16876
- async function loadLocalStepModelFsMap(circuitJson) {
16877
- const fsMap = {};
16878
- for (const element of circuitJson) {
16879
- if (!element || typeof element !== "object")
16880
- continue;
16881
- const modelUrl = element.model_step_url;
16882
- if (typeof modelUrl !== "string" || modelUrl.length === 0)
16883
- continue;
16884
- if (isRemoteUrl(modelUrl) || fsMap[modelUrl])
16885
- continue;
16886
- const localPath = path14.resolve(process.cwd(), modelUrl);
16887
- if (!existsSync2(localPath))
16888
- continue;
16889
- fsMap[modelUrl] = await readFile(localPath, "utf-8");
16890
- }
16891
- return fsMap;
16892
- }
16893
-
16894
- // lib/shared/simulation-svg-assets.ts
16895
- import {
16896
- convertCircuitJsonToSchematicSimulationSvg,
16897
- convertCircuitJsonToSimulationGraphSvg,
16898
- isSimulationExperiment,
16899
- isSimulationTransientVoltageGraph
16900
- } from "circuit-to-svg";
16901
- var isSimulationTransientCurrentGraph = (element) => element.type === "simulation_transient_current_graph";
16902
- var getSimulationSvgInputs = (circuitJson) => {
16903
- const simulationExperiment = circuitJson.find(isSimulationExperiment);
16904
- if (!simulationExperiment)
16905
- return;
16906
- const simulationTransientCurrentGraphIds = circuitJson.filter((element) => isSimulationTransientCurrentGraph(element) && element.simulation_experiment_id === simulationExperiment.simulation_experiment_id).map((element) => element.simulation_transient_current_graph_id);
16907
- const simulationTransientVoltageGraphIds = circuitJson.filter((element) => isSimulationTransientVoltageGraph(element) && element.simulation_experiment_id === simulationExperiment.simulation_experiment_id).map((element) => element.simulation_transient_voltage_graph_id);
16908
- if (simulationTransientCurrentGraphIds.length === 0 && simulationTransientVoltageGraphIds.length === 0) {
16909
- return;
16910
- }
16911
- return {
16912
- simulation_experiment_id: simulationExperiment.simulation_experiment_id,
16913
- simulation_transient_current_graph_ids: simulationTransientCurrentGraphIds,
16914
- simulation_transient_voltage_graph_ids: simulationTransientVoltageGraphIds
16915
- };
16916
- };
16917
- var getSimulationSvgAssetsFromCircuitJson = (circuitJson) => {
16918
- const simulationSvgInputs = getSimulationSvgInputs(circuitJson);
16919
- if (!simulationSvgInputs)
16920
- return;
16921
- return {
16922
- simulationSvg: convertCircuitJsonToSimulationGraphSvg({
16923
- circuitJson,
16924
- ...simulationSvgInputs
16925
- }),
16926
- schematicSimulationSvg: convertCircuitJsonToSchematicSimulationSvg({
16927
- circuitJson,
16928
- ...simulationSvgInputs
16929
- })
16930
- };
16931
- };
16932
-
16933
16990
  // cli/build/worker-output-generators.ts
16934
16991
  var writeSimulationSvgAssetsFromCircuitJson = (circuitJson, outputDir, imageFormats) => {
16935
16992
  if (!imageFormats.simulationSvgs && !imageFormats.simulationSchematicSvgs) {
@@ -16966,11 +17023,11 @@ var writeImageAssetsFromCircuitJson = async (circuitJson, options) => {
16966
17023
  const { outputDir, imageFormats, pcbSnapshotSettings } = options;
16967
17024
  fs11.mkdirSync(outputDir, { recursive: true });
16968
17025
  if (imageFormats.pcbSvgs) {
16969
- const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson, pcbSnapshotSettings);
17026
+ const pcbSvg = convertCircuitJsonToPcbSvg2(circuitJson, pcbSnapshotSettings);
16970
17027
  fs11.writeFileSync(path15.join(outputDir, "pcb.svg"), pcbSvg, "utf-8");
16971
17028
  }
16972
17029
  if (imageFormats.pcbPngs) {
16973
- const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson, pcbSnapshotSettings);
17030
+ const pcbSvg = convertCircuitJsonToPcbSvg2(circuitJson, pcbSnapshotSettings);
16974
17031
  fs11.writeFileSync(path15.join(outputDir, "pcb.png"), await convertSvgToPngBuffer(pcbSvg));
16975
17032
  }
16976
17033
  if (imageFormats.schematicSvgs) {
package/dist/cli/main.js CHANGED
@@ -39878,7 +39878,7 @@ __export2(exports_dist_3YR26ALR, {
39878
39878
  convertCircuitJsonToSchematicSvg: () => convertCircuitJsonToSchematicSvg3,
39879
39879
  convertCircuitJsonToSchematicSimulationSvg: () => convertCircuitJsonToSchematicSimulationSvg2,
39880
39880
  convertCircuitJsonToPinoutSvg: () => convertCircuitJsonToPinoutSvg,
39881
- convertCircuitJsonToPcbSvg: () => convertCircuitJsonToPcbSvg3,
39881
+ convertCircuitJsonToPcbSvg: () => convertCircuitJsonToPcbSvg4,
39882
39882
  convertCircuitJsonToAssemblySvg: () => convertCircuitJsonToAssemblySvg,
39883
39883
  circuitJsonToSchematicSvg: () => circuitJsonToSchematicSvg,
39884
39884
  circuitJsonToPcbSvg: () => circuitJsonToPcbSvg,
@@ -46226,7 +46226,7 @@ function getOutlineBounds(outline) {
46226
46226
  return;
46227
46227
  return { minX, minY, maxX, maxY };
46228
46228
  }
46229
- function convertCircuitJsonToPcbSvg3(circuitJson, options) {
46229
+ function convertCircuitJsonToPcbSvg4(circuitJson, options) {
46230
46230
  const drawPaddingOutsideBoard = options?.drawPaddingOutsideBoard ?? true;
46231
46231
  const layer = options?.layer;
46232
46232
  const colorOverrides = options?.colorOverrides;
@@ -52774,7 +52774,7 @@ var init_dist_3YR26ALR = __esm(() => {
52774
52774
  pcb_component_outside_board_error: 80,
52775
52775
  pcb_rats_nest: 85
52776
52776
  };
52777
- circuitJsonToPcbSvg = convertCircuitJsonToPcbSvg3;
52777
+ circuitJsonToPcbSvg = convertCircuitJsonToPcbSvg4;
52778
52778
  DEFAULT_BOARD_STYLE = {
52779
52779
  fill: "none",
52780
52780
  stroke: "rgb(0,0,0)",
@@ -93628,7 +93628,7 @@ var import_perfect_cli = __toESM2(require_dist2(), 1);
93628
93628
  // lib/getVersion.ts
93629
93629
  import { createRequire as createRequire2 } from "node:module";
93630
93630
  // package.json
93631
- var version = "0.1.1628";
93631
+ var version = "0.1.1631";
93632
93632
  var package_default = {
93633
93633
  name: "@tscircuit/cli",
93634
93634
  version,
@@ -97762,6 +97762,20 @@ var saveProjectConfig = (config, projectDir = process.cwd()) => {
97762
97762
  // lib/shared/autorouter-diagnostics.ts
97763
97763
  import fs16 from "node:fs";
97764
97764
  import path16 from "node:path";
97765
+ import { convertCircuitJsonToPcbSvg } from "circuit-to-svg";
97766
+
97767
+ // lib/shared/convert-svg-to-png.ts
97768
+ import { Resvg } from "@resvg/resvg-js";
97769
+ var convertSvgToPngBuffer = (svg) => {
97770
+ const resvg = new Resvg(svg, {
97771
+ fitTo: {
97772
+ mode: "original"
97773
+ }
97774
+ });
97775
+ return resvg.render().asPng();
97776
+ };
97777
+
97778
+ // lib/shared/autorouter-diagnostics.ts
97765
97779
  var DEFAULT_DEBUG_DIR = path16.join("dist", "autorouter-debug");
97766
97780
  var PROGRESS_LOG_INTERVAL_MS = 1e4;
97767
97781
  var CIRCUIT_JSON_ID_PATTERN = /\b(?:source|pcb|schematic|subcircuit|cad|simulation)_[a-z0-9_]*_\d+\b/gi;
@@ -97808,6 +97822,7 @@ class AutorouterDiagnostics {
97808
97822
  traceCountBySubcircuit = new Map;
97809
97823
  activePhase = null;
97810
97824
  completedPhaseTraces = [];
97825
+ hasWrittenPlacementSnapshot = false;
97811
97826
  summary = [];
97812
97827
  rootCircuit;
97813
97828
  constructor(options = {}) {
@@ -97840,7 +97855,6 @@ class AutorouterDiagnostics {
97840
97855
  const phaseLabel = this.getPhaseLabel(this.activePhase);
97841
97856
  const message = `Autorouter timeout after ${this.formatElapsed(elapsedMs)} in ${phaseLabel}.`;
97842
97857
  this.log(kleur_default.red(message));
97843
- this.log(`Wrote debug artifact: ${path16.relative(process.cwd(), artifactPath)}`);
97844
97858
  throw new AutorouterPhaseTimeoutError(message, artifactPath);
97845
97859
  }
97846
97860
  finalize(circuitJson) {
@@ -97882,6 +97896,11 @@ class AutorouterDiagnostics {
97882
97896
  hasLoggedStart: false,
97883
97897
  longRunningLoggingStarted: false
97884
97898
  };
97899
+ if (this.options.enabled && !this.hasWrittenPlacementSnapshot) {
97900
+ const placementCircuitJson = this.getCurrentCircuitJson().filter((element) => !this.isRouteElement(element));
97901
+ this.writePngSnapshot("placement-unrouted.png", placementCircuitJson);
97902
+ this.hasWrittenPlacementSnapshot = true;
97903
+ }
97885
97904
  if (this.options.enabled) {
97886
97905
  this.logPhaseStart(this.activePhase);
97887
97906
  }
@@ -97944,6 +97963,9 @@ class AutorouterDiagnostics {
97944
97963
  if (this.shouldDumpSuccessfulOutput(activePhase.routingPhaseIndex)) {
97945
97964
  this.writeJson(this.getPhaseFileName(activePhase, "output.traces.json"), outputSrj?.traces ?? []);
97946
97965
  }
97966
+ if (this.options.enabled) {
97967
+ this.writePngSnapshot(`phase-${activePhase.routingPhaseIndex}-routed.png`, this.getCircuitJsonWithCompletedPhaseTraces());
97968
+ }
97947
97969
  if (this.activePhase === activePhase) {
97948
97970
  this.activePhase = null;
97949
97971
  }
@@ -98103,8 +98125,54 @@ class AutorouterDiagnostics {
98103
98125
  fs16.mkdirSync(debugDir, { recursive: true });
98104
98126
  const filePath = path16.join(debugDir, fileName);
98105
98127
  fs16.writeFileSync(filePath, JSON.stringify(value, null, 2));
98128
+ this.logArtifact(filePath);
98106
98129
  return filePath;
98107
98130
  }
98131
+ writePngSnapshot(fileName, circuitJson) {
98132
+ const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
98133
+ const png = convertSvgToPngBuffer(pcbSvg);
98134
+ const debugDir = path16.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
98135
+ fs16.mkdirSync(debugDir, { recursive: true });
98136
+ const filePath = path16.join(debugDir, fileName);
98137
+ fs16.writeFileSync(filePath, png);
98138
+ this.logArtifact(filePath);
98139
+ }
98140
+ logArtifact(filePath) {
98141
+ this.log(`Wrote debug artifact: ${path16.relative(process.cwd(), filePath)}`);
98142
+ }
98143
+ getCircuitJsonWithCompletedPhaseTraces() {
98144
+ const circuitJson = [...this.getCurrentCircuitJson()];
98145
+ const elementIndexById = new Map;
98146
+ for (const [index, element] of circuitJson.entries()) {
98147
+ const id = this.getCircuitElementId(element);
98148
+ if (id)
98149
+ elementIndexById.set(id, index);
98150
+ }
98151
+ for (const trace of this.completedPhaseTraces) {
98152
+ if (!trace || typeof trace !== "object")
98153
+ continue;
98154
+ const element = trace;
98155
+ const id = this.getCircuitElementId(element);
98156
+ const existingIndex = id ? elementIndexById.get(id) : undefined;
98157
+ if (existingIndex === undefined) {
98158
+ circuitJson.push(element);
98159
+ if (id)
98160
+ elementIndexById.set(id, circuitJson.length - 1);
98161
+ } else {
98162
+ circuitJson[existingIndex] = element;
98163
+ }
98164
+ }
98165
+ return circuitJson;
98166
+ }
98167
+ getCircuitElementId(element) {
98168
+ if (typeof element.type !== "string")
98169
+ return;
98170
+ const id = element[`${element.type}_id`];
98171
+ return typeof id === "string" ? id : undefined;
98172
+ }
98173
+ isRouteElement(element) {
98174
+ return element.type === "pcb_trace" || element.type === "pcb_via";
98175
+ }
98108
98176
  getPhaseFileName(activePhase, suffix) {
98109
98177
  const phaseNumber = activePhase.routingPhaseIndex;
98110
98178
  return `phase-${phaseNumber}.${suffix}`;
@@ -105451,7 +105519,7 @@ async function generateCircuitJson({
105451
105519
  }
105452
105520
  runner.emit("renderComplete");
105453
105521
  const circuitJson = await runner.getCircuitJson();
105454
- autorouterDiagnostics.finalize(circuitJson);
105522
+ await autorouterDiagnostics.finalize(circuitJson);
105455
105523
  if (saveToFile) {
105456
105524
  debug(`Saving circuit JSON to ${outputPath}`);
105457
105525
  fs25.writeFileSync(outputPath, JSON.stringify(circuitJson, null, 2));
@@ -106157,6 +106225,9 @@ var renderCircuitJsonTo3dPng = async (circuitJson, options = {}) => {
106157
106225
  return renderGLTFToPNGFromGLB(glbArrayBuffer, getRenderCamera(circuitJson, defaultCamera, options));
106158
106226
  };
106159
106227
 
106228
+ // cli/build/worker-output-generators.ts
106229
+ import { convertCircuitJsonToGltf as convertCircuitJsonToGltf2 } from "circuit-json-to-gltf";
106230
+
106160
106231
  // node_modules/circuit-json-to-step/node_modules/stepts/dist/index.js
106161
106232
  var Entity = class {
106162
106233
  static parse(_a, _ctx) {
@@ -108443,42 +108514,11 @@ async function circuitJsonToStep(circuitJson, options = {}) {
108443
108514
  }
108444
108515
 
108445
108516
  // cli/build/worker-output-generators.ts
108446
- import { convertCircuitJsonToGltf as convertCircuitJsonToGltf2 } from "circuit-json-to-gltf";
108447
108517
  import {
108448
- convertCircuitJsonToPcbSvg,
108518
+ convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg2,
108449
108519
  convertCircuitJsonToSchematicSvg
108450
108520
  } from "circuit-to-svg";
108451
108521
 
108452
- // cli/build/worker-binary-utils.ts
108453
- var viewToArrayBuffer3 = (view) => {
108454
- const copy = new Uint8Array(view.byteLength);
108455
- copy.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
108456
- return copy.buffer;
108457
- };
108458
- var normalizeToUint8Array3 = (value) => {
108459
- if (value instanceof Uint8Array) {
108460
- return value;
108461
- }
108462
- if (value instanceof ArrayBuffer) {
108463
- return new Uint8Array(value);
108464
- }
108465
- if (ArrayBuffer.isView(value)) {
108466
- return new Uint8Array(viewToArrayBuffer3(value));
108467
- }
108468
- throw new Error("Expected Uint8Array, ArrayBuffer, or ArrayBufferView for binary data");
108469
- };
108470
-
108471
- // cli/build/svg-to-png.ts
108472
- import { Resvg } from "@resvg/resvg-js";
108473
- var convertSvgToPngBuffer = async (svg) => {
108474
- const resvg = new Resvg(svg, {
108475
- fitTo: {
108476
- mode: "original"
108477
- }
108478
- });
108479
- return resvg.render().asPng();
108480
- };
108481
-
108482
108522
  // lib/shared/load-local-step-model-fs-map.ts
108483
108523
  import { existsSync as existsSync6 } from "node:fs";
108484
108524
  import { readFile } from "node:fs/promises";
@@ -108541,6 +108581,25 @@ var getSimulationSvgAssetsFromCircuitJson = (circuitJson) => {
108541
108581
  };
108542
108582
  };
108543
108583
 
108584
+ // cli/build/worker-binary-utils.ts
108585
+ var viewToArrayBuffer3 = (view) => {
108586
+ const copy = new Uint8Array(view.byteLength);
108587
+ copy.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
108588
+ return copy.buffer;
108589
+ };
108590
+ var normalizeToUint8Array3 = (value) => {
108591
+ if (value instanceof Uint8Array) {
108592
+ return value;
108593
+ }
108594
+ if (value instanceof ArrayBuffer) {
108595
+ return new Uint8Array(value);
108596
+ }
108597
+ if (ArrayBuffer.isView(value)) {
108598
+ return new Uint8Array(viewToArrayBuffer3(value));
108599
+ }
108600
+ throw new Error("Expected Uint8Array, ArrayBuffer, or ArrayBufferView for binary data");
108601
+ };
108602
+
108544
108603
  // cli/build/worker-output-generators.ts
108545
108604
  var writeSimulationSvgAssetsFromCircuitJson = (circuitJson, outputDir, imageFormats) => {
108546
108605
  if (!imageFormats.simulationSvgs && !imageFormats.simulationSchematicSvgs) {
@@ -108577,11 +108636,11 @@ var writeImageAssetsFromCircuitJson = async (circuitJson, options) => {
108577
108636
  const { outputDir, imageFormats, pcbSnapshotSettings } = options;
108578
108637
  fs30.mkdirSync(outputDir, { recursive: true });
108579
108638
  if (imageFormats.pcbSvgs) {
108580
- const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson, pcbSnapshotSettings);
108639
+ const pcbSvg = convertCircuitJsonToPcbSvg2(circuitJson, pcbSnapshotSettings);
108581
108640
  fs30.writeFileSync(path33.join(outputDir, "pcb.svg"), pcbSvg, "utf-8");
108582
108641
  }
108583
108642
  if (imageFormats.pcbPngs) {
108584
- const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson, pcbSnapshotSettings);
108643
+ const pcbSvg = convertCircuitJsonToPcbSvg2(circuitJson, pcbSnapshotSettings);
108585
108644
  fs30.writeFileSync(path33.join(outputDir, "pcb.png"), await convertSvgToPngBuffer(pcbSvg));
108586
108645
  }
108587
108646
  if (imageFormats.schematicSvgs) {
@@ -108680,7 +108739,7 @@ var buildPreviewGltf = async ({
108680
108739
  import fs33 from "node:fs";
108681
108740
  import path36 from "node:path";
108682
108741
  import {
108683
- convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg2,
108742
+ convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg3,
108684
108743
  convertCircuitJsonToSchematicSvg as convertCircuitJsonToSchematicSvg2
108685
108744
  } from "circuit-to-svg";
108686
108745
  var generatePreviewAssets = async ({
@@ -108704,7 +108763,7 @@ var generatePreviewAssets = async ({
108704
108763
  if (imageFormats.pcbSvgs) {
108705
108764
  try {
108706
108765
  console.log(`${prefix}Generating PCB SVG...`);
108707
- const pcbSvg = convertCircuitJsonToPcbSvg2(circuitJson, pcbSnapshotSettings);
108766
+ const pcbSvg = convertCircuitJsonToPcbSvg3(circuitJson, pcbSnapshotSettings);
108708
108767
  fs33.writeFileSync(path36.join(outputDir, "pcb.svg"), pcbSvg, "utf-8");
108709
108768
  console.log(`${prefix}Written pcb.svg`);
108710
108769
  } catch (error) {
@@ -108714,7 +108773,7 @@ var generatePreviewAssets = async ({
108714
108773
  if (imageFormats.pcbPngs) {
108715
108774
  try {
108716
108775
  console.log(`${prefix}Generating PCB PNG...`);
108717
- const pcbSvg = convertCircuitJsonToPcbSvg2(circuitJson, pcbSnapshotSettings);
108776
+ const pcbSvg = convertCircuitJsonToPcbSvg3(circuitJson, pcbSnapshotSettings);
108718
108777
  fs33.writeFileSync(path36.join(outputDir, "pcb.png"), await convertSvgToPngBuffer(pcbSvg));
108719
108778
  console.log(`${prefix}Written pcb.png`);
108720
108779
  } catch (error) {
@@ -265289,7 +265348,7 @@ import path63 from "node:path";
265289
265348
  import { promisify as promisify3 } from "node:util";
265290
265349
  import { convertCircuitJsonToGltf as convertCircuitJsonToGltf4 } from "circuit-json-to-gltf";
265291
265350
  import {
265292
- convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg4,
265351
+ convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg5,
265293
265352
  convertCircuitJsonToSchematicSvg as convertCircuitJsonToSchematicSvg4,
265294
265353
  convertCircuitJsonToAssemblySvg as convertCircuitJsonToAssemblySvg2
265295
265354
  } from "circuit-to-svg";
@@ -268935,7 +268994,7 @@ var exportSnippet = async ({
268935
268994
  outputContent = convertCircuitJsonToSchematicSvg4(circuitJson);
268936
268995
  break;
268937
268996
  case "pcb-svg":
268938
- outputContent = convertCircuitJsonToPcbSvg4(circuitJson, pcbSnapshotSettings);
268997
+ outputContent = convertCircuitJsonToPcbSvg5(circuitJson, pcbSnapshotSettings);
268939
268998
  break;
268940
268999
  case "specctra-dsn":
268941
269000
  outputContent = convertCircuitJsonToDsnString(circuitJson);
@@ -290090,7 +290149,7 @@ var snapshotFilesWithWorkerPool = async (options) => {
290090
290149
  import fs66 from "node:fs";
290091
290150
  import path73 from "node:path";
290092
290151
  import {
290093
- convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg5,
290152
+ convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg6,
290094
290153
  convertCircuitJsonToSchematicSvg as convertCircuitJsonToSchematicSvg5
290095
290154
  } from "circuit-to-svg";
290096
290155
 
@@ -290174,7 +290233,7 @@ var processSnapshotFile = async ({
290174
290233
  }
290175
290234
  if (!simulationOnly) {
290176
290235
  try {
290177
- pcbSvg = convertCircuitJsonToPcbSvg5(circuitJson, {
290236
+ pcbSvg = convertCircuitJsonToPcbSvg6(circuitJson, {
290178
290237
  ...pcbSnapshotSettings,
290179
290238
  layer: pcbLayer
290180
290239
  });
@@ -2674,7 +2674,7 @@ var renderCircuitJsonTo3dPng = async (circuitJson, options = {}) => {
2674
2674
 
2675
2675
  // lib/shared/process-snapshot-file.ts
2676
2676
  import {
2677
- convertCircuitJsonToPcbSvg,
2677
+ convertCircuitJsonToPcbSvg as convertCircuitJsonToPcbSvg2,
2678
2678
  convertCircuitJsonToSchematicSvg
2679
2679
  } from "circuit-to-svg";
2680
2680
 
@@ -2801,6 +2801,20 @@ var import_make_vfs = __toESM(require_dist(), 1);
2801
2801
  // lib/shared/autorouter-diagnostics.ts
2802
2802
  import fs from "node:fs";
2803
2803
  import path from "node:path";
2804
+ import { convertCircuitJsonToPcbSvg } from "circuit-to-svg";
2805
+
2806
+ // lib/shared/convert-svg-to-png.ts
2807
+ import { Resvg } from "@resvg/resvg-js";
2808
+ var convertSvgToPngBuffer = (svg) => {
2809
+ const resvg = new Resvg(svg, {
2810
+ fitTo: {
2811
+ mode: "original"
2812
+ }
2813
+ });
2814
+ return resvg.render().asPng();
2815
+ };
2816
+
2817
+ // lib/shared/autorouter-diagnostics.ts
2804
2818
  var DEFAULT_DEBUG_DIR = path.join("dist", "autorouter-debug");
2805
2819
  var PROGRESS_LOG_INTERVAL_MS = 1e4;
2806
2820
  var CIRCUIT_JSON_ID_PATTERN = /\b(?:source|pcb|schematic|subcircuit|cad|simulation)_[a-z0-9_]*_\d+\b/gi;
@@ -2847,6 +2861,7 @@ class AutorouterDiagnostics {
2847
2861
  traceCountBySubcircuit = new Map;
2848
2862
  activePhase = null;
2849
2863
  completedPhaseTraces = [];
2864
+ hasWrittenPlacementSnapshot = false;
2850
2865
  summary = [];
2851
2866
  rootCircuit;
2852
2867
  constructor(options = {}) {
@@ -2879,7 +2894,6 @@ class AutorouterDiagnostics {
2879
2894
  const phaseLabel = this.getPhaseLabel(this.activePhase);
2880
2895
  const message = `Autorouter timeout after ${this.formatElapsed(elapsedMs)} in ${phaseLabel}.`;
2881
2896
  this.log(kleur_default.red(message));
2882
- this.log(`Wrote debug artifact: ${path.relative(process.cwd(), artifactPath)}`);
2883
2897
  throw new AutorouterPhaseTimeoutError(message, artifactPath);
2884
2898
  }
2885
2899
  finalize(circuitJson) {
@@ -2921,6 +2935,11 @@ class AutorouterDiagnostics {
2921
2935
  hasLoggedStart: false,
2922
2936
  longRunningLoggingStarted: false
2923
2937
  };
2938
+ if (this.options.enabled && !this.hasWrittenPlacementSnapshot) {
2939
+ const placementCircuitJson = this.getCurrentCircuitJson().filter((element) => !this.isRouteElement(element));
2940
+ this.writePngSnapshot("placement-unrouted.png", placementCircuitJson);
2941
+ this.hasWrittenPlacementSnapshot = true;
2942
+ }
2924
2943
  if (this.options.enabled) {
2925
2944
  this.logPhaseStart(this.activePhase);
2926
2945
  }
@@ -2983,6 +3002,9 @@ class AutorouterDiagnostics {
2983
3002
  if (this.shouldDumpSuccessfulOutput(activePhase.routingPhaseIndex)) {
2984
3003
  this.writeJson(this.getPhaseFileName(activePhase, "output.traces.json"), outputSrj?.traces ?? []);
2985
3004
  }
3005
+ if (this.options.enabled) {
3006
+ this.writePngSnapshot(`phase-${activePhase.routingPhaseIndex}-routed.png`, this.getCircuitJsonWithCompletedPhaseTraces());
3007
+ }
2986
3008
  if (this.activePhase === activePhase) {
2987
3009
  this.activePhase = null;
2988
3010
  }
@@ -3142,8 +3164,54 @@ class AutorouterDiagnostics {
3142
3164
  fs.mkdirSync(debugDir, { recursive: true });
3143
3165
  const filePath = path.join(debugDir, fileName);
3144
3166
  fs.writeFileSync(filePath, JSON.stringify(value, null, 2));
3167
+ this.logArtifact(filePath);
3145
3168
  return filePath;
3146
3169
  }
3170
+ writePngSnapshot(fileName, circuitJson) {
3171
+ const pcbSvg = convertCircuitJsonToPcbSvg(circuitJson);
3172
+ const png = convertSvgToPngBuffer(pcbSvg);
3173
+ const debugDir = path.resolve(this.options.debugDir ?? DEFAULT_DEBUG_DIR);
3174
+ fs.mkdirSync(debugDir, { recursive: true });
3175
+ const filePath = path.join(debugDir, fileName);
3176
+ fs.writeFileSync(filePath, png);
3177
+ this.logArtifact(filePath);
3178
+ }
3179
+ logArtifact(filePath) {
3180
+ this.log(`Wrote debug artifact: ${path.relative(process.cwd(), filePath)}`);
3181
+ }
3182
+ getCircuitJsonWithCompletedPhaseTraces() {
3183
+ const circuitJson = [...this.getCurrentCircuitJson()];
3184
+ const elementIndexById = new Map;
3185
+ for (const [index, element] of circuitJson.entries()) {
3186
+ const id = this.getCircuitElementId(element);
3187
+ if (id)
3188
+ elementIndexById.set(id, index);
3189
+ }
3190
+ for (const trace of this.completedPhaseTraces) {
3191
+ if (!trace || typeof trace !== "object")
3192
+ continue;
3193
+ const element = trace;
3194
+ const id = this.getCircuitElementId(element);
3195
+ const existingIndex = id ? elementIndexById.get(id) : undefined;
3196
+ if (existingIndex === undefined) {
3197
+ circuitJson.push(element);
3198
+ if (id)
3199
+ elementIndexById.set(id, circuitJson.length - 1);
3200
+ } else {
3201
+ circuitJson[existingIndex] = element;
3202
+ }
3203
+ }
3204
+ return circuitJson;
3205
+ }
3206
+ getCircuitElementId(element) {
3207
+ if (typeof element.type !== "string")
3208
+ return;
3209
+ const id = element[`${element.type}_id`];
3210
+ return typeof id === "string" ? id : undefined;
3211
+ }
3212
+ isRouteElement(element) {
3213
+ return element.type === "pcb_trace" || element.type === "pcb_via";
3214
+ }
3147
3215
  getPhaseFileName(activePhase, suffix) {
3148
3216
  const phaseNumber = activePhase.routingPhaseIndex;
3149
3217
  return `phase-${phaseNumber}.${suffix}`;
@@ -3474,7 +3542,7 @@ async function generateCircuitJson({
3474
3542
  }
3475
3543
  runner.emit("renderComplete");
3476
3544
  const circuitJson = await runner.getCircuitJson();
3477
- autorouterDiagnostics.finalize(circuitJson);
3545
+ await autorouterDiagnostics.finalize(circuitJson);
3478
3546
  if (saveToFile) {
3479
3547
  debug(`Saving circuit JSON to ${outputPath}`);
3480
3548
  fs4.writeFileSync(outputPath, JSON.stringify(circuitJson, null, 2));
@@ -3690,7 +3758,7 @@ var processSnapshotFile = async ({
3690
3758
  }
3691
3759
  if (!simulationOnly) {
3692
3760
  try {
3693
- pcbSvg = convertCircuitJsonToPcbSvg(circuitJson, {
3761
+ pcbSvg = convertCircuitJsonToPcbSvg2(circuitJson, {
3694
3762
  ...pcbSnapshotSettings,
3695
3763
  layer: pcbLayer
3696
3764
  });
package/dist/lib/index.js CHANGED
@@ -65811,7 +65811,7 @@ var getNodeHandler = (winterSpec, { port, middleware = [] }) => {
65811
65811
  }));
65812
65812
  };
65813
65813
  // package.json
65814
- var version = "0.1.1628";
65814
+ var version = "0.1.1631";
65815
65815
  var package_default = {
65816
65816
  name: "@tscircuit/cli",
65817
65817
  version,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/cli",
3
- "version": "0.1.1631",
3
+ "version": "0.1.1632",
4
4
  "main": "dist/cli/main.js",
5
5
  "exports": {
6
6
  ".": "./dist/cli/main.js",