@enerlence/suntropy-cli 0.11.0 → 0.11.2

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.
@@ -2149,6 +2149,47 @@ function getGlobalOpts7(cmd) {
2149
2149
  function resolveFile(opts) {
2150
2150
  return opts.file || process.env.SUNTROPY_STUDY || "./study.json";
2151
2151
  }
2152
+ function resolveSurfaceCoordinates(surface, study) {
2153
+ const isValid = (c) => {
2154
+ const p = c;
2155
+ return !!p && Number.isFinite(p.lat) && Number.isFinite(p.lng);
2156
+ };
2157
+ const center = surface.center;
2158
+ if (isValid(center)) return { lat: center.lat, lng: center.lng };
2159
+ const studyLocation = study.location;
2160
+ if (isValid(studyLocation)) return { lat: studyLocation.lat, lng: studyLocation.lng };
2161
+ const path = surface.polygonPath;
2162
+ if (Array.isArray(path) && path.length > 0) {
2163
+ const points = path.filter(
2164
+ (p) => Number.isFinite(p?.lat) && Number.isFinite(p?.lng)
2165
+ );
2166
+ if (points.length > 0) {
2167
+ const sum = points.reduce(
2168
+ (acc, p) => ({ lat: acc.lat + p.lat, lng: acc.lng + p.lng }),
2169
+ { lat: 0, lng: 0 }
2170
+ );
2171
+ const centroid = { lat: sum.lat / points.length, lng: sum.lng / points.length };
2172
+ if (isValid(centroid)) return centroid;
2173
+ return { lat: points[0].lat, lng: points[0].lng };
2174
+ }
2175
+ }
2176
+ return null;
2177
+ }
2178
+ function resolveSurfaceInstalledPower(surface, study) {
2179
+ const explicit = surface.installedPower;
2180
+ if (Number.isFinite(explicit) && explicit > 0) {
2181
+ return { installedPower: explicit, isDefault: false };
2182
+ }
2183
+ const solarPanel = study.solarPanel;
2184
+ const kitPanel = study.solarKit?.kitSolarPanel;
2185
+ const panelPeakPower = solarPanel?.peakPower || kitPanel?.peakPower || void 0;
2186
+ const layout = surface.panelsLayoutPolygons;
2187
+ const panelCount = layout !== void 0 ? layout.length || 0 : surface.panelNumber;
2188
+ if (panelPeakPower && Number.isFinite(panelCount) && panelCount > 0) {
2189
+ return { installedPower: panelCount * panelPeakPower, isDefault: false };
2190
+ }
2191
+ return { installedPower: 5e3, isDefault: true };
2192
+ }
2152
2193
  function registerStudyBuilderCommands(studies) {
2153
2194
  studies.command("init").description(
2154
2195
  'Create a new study workspace (local JSON file with defaults).\nExample: suntropy studies init --file /tmp/study.json --name "Residencial 5kW"'
@@ -2694,18 +2735,22 @@ Example: suntropy studies set data --file study.json --data '{"referenceId":"REF
2694
2735
  for (const idx of indicesToCalc) {
2695
2736
  const surface = surfaces[idx];
2696
2737
  if (!surface) continue;
2697
- const center = surface.center;
2698
- const studyLocation = study.location;
2699
- const lat = center?.lat || studyLocation?.lat;
2700
- const lng = center?.lng || studyLocation?.lng;
2701
- if (!lat || !lng) {
2738
+ const coords = resolveSurfaceCoordinates(surface, study);
2739
+ if (!coords) {
2702
2740
  outputError(new Error(`Surface ${idx} has no coordinates. Use: studies add surface --lat N --lon N`));
2703
2741
  continue;
2704
2742
  }
2743
+ const { lat, lng } = coords;
2744
+ const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);
2745
+ if (isDefault) {
2746
+ outputError(new Error(
2747
+ `Surface ${idx} has no resolvable installed power (no installedPower, and no panel layout / panelNumber with a solarPanel/solarKit peak power). Using the 5000W default \u2014 production will be wrong. Set the panels and kit/panel before calculating.`
2748
+ ));
2749
+ }
2705
2750
  const body = {
2706
2751
  lat,
2707
2752
  long: lng,
2708
- instaledPower: surface.installedPower || 5e3,
2753
+ instaledPower: installedPower,
2709
2754
  angle: surface.inclination || surface.angle || 30,
2710
2755
  azimuth: surface.orientation || surface.azimuth || 180,
2711
2756
  lossesPercentage: parseFloat(opts.losses),
@@ -2959,7 +3004,7 @@ Example: suntropy studies set data --file study.json --data '{"referenceId":"REF
2959
3004
  surface.panelInclination || 0,
2960
3005
  surface.inclination || 0,
2961
3006
  surface.panelPosition || "vertical",
2962
- surface.polygonPath?.[0]?.lat || 37
3007
+ resolveSurfaceCoordinates(surface, study)?.lat ?? 37
2963
3008
  );
2964
3009
  } else {
2965
3010
  maxPanels = remainingPanels;
@@ -3071,7 +3116,7 @@ Example: suntropy studies set data --file study.json --data '{"referenceId":"REF
3071
3116
  surface.panelInclination || 0,
3072
3117
  surface.inclination || 0,
3073
3118
  surface.panelPosition || "vertical",
3074
- surface.polygonPath?.[0]?.lat || 37
3119
+ resolveSurfaceCoordinates(surface, study)?.lat ?? 37
3075
3120
  );
3076
3121
  surfacesMaxPeakPower[sid] = maxPanels * panelPeakPower / 1e3;
3077
3122
  } else {
@@ -4553,7 +4598,7 @@ function registerCommandProfileCommand(program2) {
4553
4598
  }
4554
4599
 
4555
4600
  // src/index.ts
4556
- var CLI_VERSION = true ? "0.11.0" : "0.0.0-dev";
4601
+ var CLI_VERSION = true ? "0.11.2" : "0.0.0-dev";
4557
4602
  function createProgram() {
4558
4603
  const program2 = new Command3();
4559
4604
  program2.name("suntropy").description("Agent-first CLI for Suntropy solar platform. Optimized for programmatic data manipulation and progressive exploration.").version(CLI_VERSION).option("--format <format>", "Output format: json (default), human, csv", "json").option("--fields <fields>", "Comma-separated fields to include in output").option("--server <url>", "Override API server URL").option("--token <jwt>", "Override authentication token").option("--profile <name>", "Use a specific config profile").option("--verbose", "Show HTTP request/response details on stderr").option("--quiet", "Suppress non-data output").option("--save <file>", "Save output to file (also writes to stdout)");