klio 1.2.6 → 1.2.7

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
@@ -119,6 +119,7 @@ Aspekte für Mond:
119
119
 
120
120
  Diese Analyse basiert auf der aktuellen Planetenposition.
121
121
  ```
122
+ Kombiniere mit `--i --tr` und `--hs koch` für persönliche Transit-Aspekte
122
123
 
123
124
  ### Aspekte für einen Planeten (Geburtshoroskop)
124
125
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klio",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "description": "Eine CLI für astrologische Berechnungen",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -148,7 +148,6 @@ function calculateHouses(julianDay, houseSystem = 'K', useBirthLocation = false)
148
148
  latitude = config.birthData.location.latitude;
149
149
  longitude = config.birthData.location.longitude;
150
150
  locationName = `${config.birthData.location.name}, ${config.birthData.location.country}`;
151
- console.log(`Verwende Geburtsort: ${locationName} (${latitude}° Breitengrad, ${longitude}° Längengrad)`);
152
151
  } else if (useBirthLocation) {
153
152
  // Geburtsort ist konfiguriert, aber kein Standort - verwende Standardort
154
153
  latitude = defaultLatitude;
@@ -480,19 +479,19 @@ function findExactAspectTime(planet1, planet2, aspectType, startDate) {
480
479
  return null;
481
480
  }
482
481
 
483
- // Wir suchen in einem größeren Zeitfenster (180 Tage vor und nach dem Startdatum)
484
- // um den exakten Aspekt zu finden, egal ob in Vergangenheit oder Zukunft
482
+ // Wir suchen in einem vernünftigen Zeitfenster (90 Tage in der Zukunft)
483
+ // um den nächsten exakten Aspekt zu finden
485
484
  // Besonders wichtig für langsame Planeten wie Saturn, Uranus, Neptun, Pluto
486
485
  let bestMatch = null;
487
486
  let bestDistance = Infinity;
488
487
 
489
- // Suche in einem Zeitfenster von 180 Tagen vor und nach dem Startdatum
490
- const searchWindow = 180; // Tage
488
+ // Suche nur in der Zukunft (0-90 Tage nach dem Startdatum)
489
+ const searchWindow = 90; // Tage
491
490
 
492
- // Wir suchen auch in kleineren Schritten (alle 3 Stunden), um präzisere Ergebnisse zu erhalten
493
- const stepsPerDay = 8; // 3-Stunden-Schritte
491
+ // Wir suchen in kleineren Schritten (alle 2 Stunden), um präzisere Ergebnisse zu erhalten
492
+ const stepsPerDay = 12; // 2-Stunden-Schritte
494
493
 
495
- for (let daysOffset = -searchWindow; daysOffset <= searchWindow; daysOffset++) {
494
+ for (let daysOffset = 0; daysOffset <= searchWindow; daysOffset++) {
496
495
  for (let hourOffset = 0; hourOffset < 24; hourOffset++) { // Jede Stunde
497
496
  for (let minuteOffset = 0; minuteOffset < 60; minuteOffset += 5) { // Alle 5 Minuten
498
497
  const testDate = addDays(startDate, daysOffset);
@@ -518,7 +517,56 @@ function findExactAspectTime(planet1, planet2, aspectType, startDate) {
518
517
  }
519
518
 
520
519
  // Wenn wir einen Aspekt gefunden haben, der nah genug am Ziel ist, geben wir ihn zurück
521
- if (bestMatch && bestDistance <= 1.0) { // Toleranz von 1.0°
520
+ // Strengere Toleranz von 0. für bessere Genauigkeit
521
+ if (bestMatch && bestDistance <= 0.5) { // Toleranz von 0.5°
522
+ return bestMatch;
523
+ }
524
+
525
+ return null;
526
+ }
527
+
528
+ // Funktion zum Finden des letzten exakten Aspekts in der Vergangenheit (für separative Phasen)
529
+ function findLastExactAspectTime(planet1, planet2, aspectType, startDate) {
530
+ const targetAngle = getAspectAngle(aspectType);
531
+
532
+ if (targetAngle === null) {
533
+ return null;
534
+ }
535
+
536
+ // Suche in der Vergangenheit (bis zu 180 Tage vor dem Startdatum)
537
+ let bestMatch = null;
538
+ let bestDistance = Infinity;
539
+
540
+ // Suche in einem Zeitfenster von 180 Tagen vor dem Startdatum
541
+ const searchWindow = 180; // Tage
542
+
543
+ for (let daysOffset = -searchWindow; daysOffset <= 0; daysOffset++) {
544
+ for (let hourOffset = 0; hourOffset < 24; hourOffset++) { // Jede Stunde
545
+ for (let minuteOffset = 0; minuteOffset < 60; minuteOffset += 5) { // Alle 5 Minuten
546
+ const testDate = addDays(startDate, daysOffset);
547
+ testDate.hour = hourOffset;
548
+ testDate.minute = minuteOffset;
549
+
550
+ // Berechne die Positionen der beiden Planeten
551
+ const planet1Data = getAstrologicalData(planet1, testDate);
552
+ const planet2Data = getAstrologicalData(planet2, testDate);
553
+
554
+ // Berechne den Winkel zwischen den Planeten
555
+ const angleDiff = Math.abs(planet1Data.longitude - planet2Data.longitude) % 360;
556
+ const normalizedAngle = Math.min(angleDiff, 360 - angleDiff);
557
+ const distanceToTarget = Math.abs(normalizedAngle - targetAngle);
558
+
559
+ // Speichere das beste Ergebnis
560
+ if (distanceToTarget < bestDistance) {
561
+ bestDistance = distanceToTarget;
562
+ bestMatch = {...testDate};
563
+ }
564
+ }
565
+ }
566
+ }
567
+
568
+ // Wenn wir einen Aspekt gefunden haben, der nah genug am Ziel ist, geben wir ihn zurück
569
+ if (bestMatch && bestDistance <= 0.5) { // Toleranz von 0.5°
522
570
  return bestMatch;
523
571
  }
524
572
 
@@ -1132,6 +1180,214 @@ async function calculatePersonalTransits(transitDate = null, birthData = null) {
1132
1180
  };
1133
1181
  }
1134
1182
 
1183
+ // Funktion zur Berechnung persönlicher Transit-Aspekte
1184
+ function calculatePersonalTransitAspects(transitDate = null, birthData = null, targetPlanet = null) {
1185
+ if (!birthData) {
1186
+ birthData = getBirthDataFromConfig();
1187
+ if (!birthData) {
1188
+ console.error('Keine Geburtsdaten verfügbar für persönliche Transit-Aspekte.');
1189
+ return null;
1190
+ }
1191
+ }
1192
+
1193
+ // Verwende aktuelles Datum, wenn kein Transitdatum angegeben
1194
+ if (!transitDate) {
1195
+ transitDate = getCurrentTimeInTimezone();
1196
+ }
1197
+
1198
+ // Berechne aktuelle Planetenpositionen (Transit)
1199
+ const transitPlanets = {};
1200
+ for (const [name, planetId] of Object.entries(planets)) {
1201
+ const data = getAstrologicalData(name, transitDate);
1202
+ transitPlanets[name] = data.longitude;
1203
+ }
1204
+
1205
+ // Berechne Geburtsplanetenpositionen (Radix)
1206
+ const birthPlanets = {};
1207
+ for (const [name, planetId] of Object.entries(planets)) {
1208
+ const data = getAstrologicalData(name, birthData);
1209
+ birthPlanets[name] = data.longitude;
1210
+ }
1211
+
1212
+ // Berechne Aspekte zwischen Transit- und Geburtsplaneten
1213
+ const aspects = [];
1214
+ const aspectTypes = [
1215
+ { name: 'Konjunktion', angle: 0, orb: 8 },
1216
+ { name: 'Opposition', angle: 180, orb: 8 },
1217
+ { name: 'Quadrat', angle: 90, orb: 6 },
1218
+ { name: 'Trigon', angle: 120, orb: 6 },
1219
+ { name: 'Sextil', angle: 60, orb: 4 }
1220
+ ];
1221
+
1222
+ // Vergleiche jeden Transitplaneten mit jedem Geburtsplaneten
1223
+ for (const [transitName, transitLongitude] of Object.entries(transitPlanets)) {
1224
+ for (const [birthName, birthLongitude] of Object.entries(birthPlanets)) {
1225
+ // Überspringe, wenn es sich um denselben Planeten handelt
1226
+ if (transitName === birthName) continue;
1227
+
1228
+ // Berechne den Winkelunterschied
1229
+ const angleDiff = Math.abs(transitLongitude - birthLongitude) % 360;
1230
+ const normalizedAngle = Math.min(angleDiff, 360 - angleDiff);
1231
+
1232
+ // Prüfe auf Aspekte
1233
+ for (const aspect of aspectTypes) {
1234
+ if (Math.abs(normalizedAngle - aspect.angle) <= aspect.orb) {
1235
+ aspects.push({
1236
+ transitPlanet: transitName,
1237
+ birthPlanet: birthName,
1238
+ type: aspect.name,
1239
+ angle: normalizedAngle.toFixed(2),
1240
+ orb: Math.abs(normalizedAngle - aspect.angle).toFixed(2),
1241
+ transitLongitude: transitLongitude,
1242
+ birthLongitude: birthLongitude
1243
+ });
1244
+ }
1245
+ }
1246
+ }
1247
+ }
1248
+
1249
+ // Filtere nach Zielplanet, falls angegeben
1250
+ const filteredAspects = targetPlanet
1251
+ ? aspects.filter(aspect => aspect.transitPlanet === targetPlanet)
1252
+ : aspects;
1253
+
1254
+ return {
1255
+ transitDate: transitDate,
1256
+ birthData: birthData,
1257
+ aspects: filteredAspects
1258
+ };
1259
+ }
1260
+
1261
+ // Funktion zur Anzeige persönlicher Transit-Aspekte
1262
+ function showPersonalTransitAspects(transitDate = null, birthData = null, targetPlanet = null) {
1263
+ const aspectData = calculatePersonalTransitAspects(transitDate, birthData, targetPlanet);
1264
+
1265
+ if (!aspectData || aspectData.aspects.length === 0) {
1266
+ console.log('Keine persönlichen Transit-Aspekte gefunden.');
1267
+ return;
1268
+ }
1269
+
1270
+ const transitDateDisplay = transitDate || getCurrentTimeInTimezone();
1271
+ console.log(`Persönliche Transit-Aspekte (${transitDateDisplay.day}.${transitDateDisplay.month}.${transitDateDisplay.year}):`);
1272
+ console.log('================================================================================');
1273
+ console.log('| Transit | Geburts | Aspekt | Orb | Transit Pos | Geburts Pos |');
1274
+ console.log('================================================================================');
1275
+
1276
+ // Hole zusätzliche Informationen für die Anzeige
1277
+ const transitPlanetsData = {};
1278
+ const birthPlanetsData = {};
1279
+
1280
+ for (const [name] of Object.entries(planets)) {
1281
+ transitPlanetsData[name] = getAstrologicalData(name, transitDateDisplay);
1282
+ birthPlanetsData[name] = getAstrologicalData(name, birthData);
1283
+ }
1284
+
1285
+ aspectData.aspects.forEach(aspect => {
1286
+ const transitPlanetData = transitPlanetsData[aspect.transitPlanet];
1287
+ const birthPlanetData = birthPlanetsData[aspect.birthPlanet];
1288
+
1289
+ const transitPlanetFormatted = aspect.transitPlanet.charAt(0).toUpperCase() + aspect.transitPlanet.slice(1);
1290
+ const birthPlanetFormatted = aspect.birthPlanet.charAt(0).toUpperCase() + aspect.birthPlanet.slice(1);
1291
+ const aspectName = aspect.type.padEnd(11, ' ');
1292
+ const orb = aspect.orb.padEnd(4, ' ');
1293
+ const transitPos = `${transitPlanetData.sign} ${transitPlanetData.degreeInSign}°`;
1294
+ const birthPos = `${birthPlanetData.sign} ${birthPlanetData.degreeInSign}°`;
1295
+
1296
+ console.log(`| ${transitPlanetFormatted.padEnd(10)} | ${birthPlanetFormatted.padEnd(10)} | ${aspectName} | ${orb}° | ${transitPos.padEnd(11)} | ${birthPos.padEnd(11)} |`);
1297
+ });
1298
+
1299
+ console.log('================================================================================');
1300
+ console.log(`Gesamt: ${aspectData.aspects.length} persönliche Transit-Aspekte gefunden`);
1301
+ console.log('\nErklärung: Diese Aspekte zeigen, wie die aktuellen Planetenpositionen');
1302
+ console.log('mit deinen Geburtspositionen interagieren (Transit → Radix).');
1303
+ }
1304
+
1305
+ // Funktion für kombinierte Analyse (Geburts- und Transit-Aspekte mit Häusern)
1306
+ async function showCombinedAnalysis(planetName, transitDate = null, birthData = null, houseSystem = 'K') {
1307
+ if (!birthData) {
1308
+ birthData = getBirthDataFromConfig();
1309
+ if (!birthData) {
1310
+ console.error('Keine Geburtsdaten verfügbar für kombinierte Analyse.');
1311
+ return null;
1312
+ }
1313
+ }
1314
+
1315
+ // Verwende aktuelles Datum, wenn kein Transitdatum angegeben
1316
+ if (!transitDate) {
1317
+ transitDate = getCurrentTimeInTimezone();
1318
+ }
1319
+
1320
+ // Berechne Häuser basierend auf Geburtsdaten
1321
+ const birthJulianDay = calculateJulianDayUTC(birthData, getTimezoneOffset(birthData, birthData.location?.timezone || 'Europe/Zurich'));
1322
+ const houses = await calculateHouses(birthJulianDay, houseSystem === 'koch' ? 'K' : houseSystem === 'wholesign' ? 'W' : 'G', true);
1323
+
1324
+ // Berechne aktuelle Planetenpositionen (Transit)
1325
+ const transitPlanetData = getAstrologicalData(planetName, transitDate);
1326
+ const transitLongitude = transitPlanetData.longitude;
1327
+ const transitHouse = getPlanetHouse(transitLongitude, houses.house);
1328
+
1329
+ // Berechne Geburtsplanetenpositionen (Radix)
1330
+ const birthPlanetData = getAstrologicalData(planetName, birthData);
1331
+ const birthLongitude = birthPlanetData.longitude;
1332
+ const birthHouse = getPlanetHouse(birthLongitude, houses.house);
1333
+
1334
+ // Berechne Geburtsaspekte für den Planeten
1335
+ const birthAspects = calculatePlanetAspects(planetName, birthData, true);
1336
+
1337
+ // Berechne Transit-Aspekte für den Planeten
1338
+ const transitAspectsData = calculatePersonalTransitAspects(transitDate, birthData, planetName);
1339
+ const transitAspects = transitAspectsData ? transitAspectsData.aspects : [];
1340
+
1341
+ // Zeige kombinierte Analyse an
1342
+ console.log(`Kombinierte Analyse für ${planetName.charAt(0).toUpperCase() + planetName.slice(1)}:`);
1343
+ console.log('================================================================================');
1344
+ console.log(`Analyse-Datum: ${transitDate.day}.${transitDate.month}.${transitDate.year}`);
1345
+ console.log(`Geburtsdatum: ${birthData.day}.${birthData.month}.${birthData.year} ${birthData.hour}:${birthData.minute.toString().padStart(2, '0')}`);
1346
+ console.log(`Haus-System: ${houseSystem.charAt(0).toUpperCase() + houseSystem.slice(1)} (basierend auf Geburts-ASC)`);
1347
+ console.log('');
1348
+
1349
+ // Zeige Planetenpositionen und Häuser
1350
+ console.log('Positionen und Häuser:');
1351
+ console.log('--------------------------------------------------------------------------------');
1352
+ console.log(`Transit: ${transitPlanetData.sign} ${transitPlanetData.degreeInSign}° (Haus ${transitHouse})`);
1353
+ console.log(`Geburt: ${birthPlanetData.sign} ${birthPlanetData.degreeInSign}° (Haus ${birthHouse})`);
1354
+ console.log('');
1355
+
1356
+ // Zeige Geburtsaspekte
1357
+ if (birthAspects.length > 0) {
1358
+ console.log('Geburtsaspekte (Radix → Radix):');
1359
+ console.log('--------------------------------------------------------------------------------');
1360
+ birthAspects.forEach(aspect => {
1361
+ const aspectPlanetData = getAstrologicalData(aspect.planet, birthData);
1362
+ const aspectHouse = getPlanetHouse(parseFloat(aspectPlanetData.degreeInSign) + (signs.indexOf(aspectPlanetData.sign) * 30), houses.house);
1363
+ console.log(`${aspect.type.padEnd(12)} mit ${aspect.planet.padEnd(8)} (${aspectPlanetData.sign} ${aspectPlanetData.degreeInSign}° Haus ${aspectHouse}) - Orb: ${aspect.orb}°`);
1364
+ });
1365
+ console.log('');
1366
+ }
1367
+
1368
+ // Zeige Transit-Aspekte
1369
+ if (transitAspects.length > 0) {
1370
+ console.log('Transit-Aspekte (Transit → Radix):');
1371
+ console.log('--------------------------------------------------------------------------------');
1372
+ transitAspects.forEach(aspect => {
1373
+ const birthPlanetData = getAstrologicalData(aspect.birthPlanet, birthData);
1374
+ const birthHouse = getPlanetHouse(parseFloat(birthPlanetData.degreeInSign) + (signs.indexOf(birthPlanetData.sign) * 30), houses.house);
1375
+ console.log(`${aspect.type.padEnd(12)} mit ${aspect.birthPlanet.padEnd(8)} (${birthPlanetData.sign} ${birthPlanetData.degreeInSign}° Haus ${birthHouse}) - Orb: ${aspect.orb}°`);
1376
+ });
1377
+ console.log('');
1378
+ }
1379
+
1380
+ return {
1381
+ transitPlanetData,
1382
+ birthPlanetData,
1383
+ transitHouse,
1384
+ birthHouse,
1385
+ birthAspects,
1386
+ transitAspects,
1387
+ houses
1388
+ };
1389
+ }
1390
+
1135
1391
  // Funktion zur Analyse der Elementverteilung
1136
1392
  function analyzeElementDistribution(dateComponents, useBirthData = false) {
1137
1393
  const elementCounts = {
@@ -1321,9 +1577,13 @@ module.exports = {
1321
1577
  getAspectAngle,
1322
1578
  getFutureAspects,
1323
1579
  findExactAspectTime,
1580
+ findLastExactAspectTime,
1324
1581
  detectAspectFigures,
1325
1582
  showAspectFigures,
1326
- calculatePersonalTransits
1583
+ calculatePersonalTransits,
1584
+ calculatePersonalTransitAspects,
1585
+ showPersonalTransitAspects,
1586
+ showCombinedAnalysis
1327
1587
  };
1328
1588
 
1329
1589
  // Funktion zur Berechnung vergangener Aspekte zwischen zwei Planeten
package/src/cli/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const { Command } = require('commander');
2
2
  const { planets, signs } = require('../astrology/astrologyConstants');
3
3
  const { showRetrogradePlanets } = require('../astrology/retrogradeService');
4
- const { getCurrentTimeInTimezone, showAspectFigures, analyzeElementDistribution, getTimezoneOffset, calculateJulianDayUTC, calculateHouses, getAstrologicalData, getPlanetHouse, showPlanetAspects, calculatePlanetAspects, getAllActiveAspects, showAllActiveAspects, getBirthDataFromConfig, detectAspectFigures, calculatePersonalTransits } = require('../astrology/astrologyService');
4
+ const { getCurrentTimeInTimezone, showAspectFigures, analyzeElementDistribution, getTimezoneOffset, calculateJulianDayUTC, calculateHouses, getAstrologicalData, getPlanetHouse, showPlanetAspects, calculatePlanetAspects, getAllActiveAspects, showAllActiveAspects, getBirthDataFromConfig, detectAspectFigures, calculatePersonalTransits, showPersonalTransitAspects, showCombinedAnalysis, calculatePersonalTransitAspects, determineAspectPhase, findExactAspectTime, findLastExactAspectTime } = require('../astrology/astrologyService');
5
5
  const { performSetup, showConfigStatus, loadConfig, setAIModel, askAIModel } = require('../config/configService');
6
6
  const { parseAppleHealthXML } = require('../health/healthService');
7
7
  const { analyzeStepsByPlanetSign, analyzeStressByPlanetAspects, analyzePlanetAspectsForSleep } = require('../health/healthAnalysis');
@@ -110,6 +110,8 @@ program
110
110
  .option('--el', 'Zeigt die Elementverteilung der Planeten in einem horizontalen Chart an')
111
111
  .option('--af', 'Zeigt aktive Aspektfiguren wie T-Quadrate, Große Trigone, etc. an')
112
112
  .option('--transite', 'Zeigt persönliche Transite basierend auf Geburtsdaten an')
113
+ .option('--transit-aspekte', 'Zeigt persönliche Transit-Aspekte (Transit → Radix) an')
114
+ .option('--tr', 'Zeigt persönliche Transit-Aspekte (Transit → Radix) an (Kurzform)')
113
115
  .option('--v <count>', 'Zeigt vergangene Aspekte zwischen zwei Planeten an (Format: --v <count> planet1 aspectType planet2)')
114
116
  .option('--z <count>', 'Zeigt zukünftige Aspekte zwischen zwei Planeten an (Format: --z <count> planet1 aspectType planet2)')
115
117
  .description('Zeigt astrologische Daten für einen Planeten an')
@@ -408,6 +410,186 @@ program
408
410
  return;
409
411
  }
410
412
 
413
+ // Kombinierte Analyse anzeigen, falls --a --i und --tr (oder --transit-aspekte) zusammen mit --hs angegeben
414
+ if ((options.a && shouldUseBirthData(options) && (options.transitAspekte || options.tr)) ||
415
+ (options.transitAspekte || options.tr) && options.hs) {
416
+
417
+ // Geburtsdaten sind erforderlich
418
+ const birthData = getBirthDataFromConfig();
419
+ if (!birthData) {
420
+ console.error('Fehler: Kombinierte Analyse erfordert Geburtsdaten. Bitte führe --setup aus.');
421
+ process.exit(1);
422
+ }
423
+
424
+ // Benutzerdefiniertes Datum verwenden, falls angegeben
425
+ let transitDate = null;
426
+ if (options.d) {
427
+ // Versuche, das Datum als DD.MM.YYYY oder DD.MM.YYYY HH:MM zu parsen
428
+ const dateRegex = /^(\d{1,2})\.(\d{1,2})\.(\d{4})(?:\s+(\d{1,2}):(\d{2}))?$/;
429
+ const match = options.d.match(dateRegex);
430
+
431
+ if (match) {
432
+ const day = parseInt(match[1], 10);
433
+ const month = parseInt(match[2], 10);
434
+ const year = parseInt(match[3], 10);
435
+ const hour = match[4] ? parseInt(match[4], 10) : 12; // Standard: 12 Uhr
436
+ const minute = match[5] ? parseInt(match[5], 10) : 0; // Standard: 0 Minuten
437
+
438
+ // Überprüfe, ob das Datum gültig ist
439
+ const date = new Date(year, month - 1, day, hour, minute);
440
+ if (date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day) {
441
+ transitDate = {
442
+ day: day,
443
+ month: month,
444
+ year: year,
445
+ hour: hour,
446
+ minute: minute
447
+ };
448
+ } else {
449
+ console.error('Ungültiges Datum:', options.d);
450
+ console.error('💡 Bitte verwende das Format: DD.MM.YYYY oder "DD.MM.YYYY HH:MM"');
451
+ process.exit(1);
452
+ }
453
+ } else {
454
+ console.error('Ungültiges Datum:', options.d);
455
+ console.error('💡 Bitte verwende das Format: DD.MM.YYYY oder "DD.MM.YYYY HH:MM"');
456
+ process.exit(1);
457
+ }
458
+ }
459
+
460
+ // Haus-System bestimmen
461
+ const houseSystem = options.hs ? options.hs.toLowerCase() : 'koch';
462
+
463
+ // Zeige kombinierte Analyse an
464
+ const targetPlanet = planetArg ? planetArg.toLowerCase() : null;
465
+ if (targetPlanet) {
466
+ await showCombinedAnalysis(targetPlanet, transitDate, birthData, houseSystem);
467
+ } else {
468
+ // Wenn kein Planet angegeben ist, zeige NUR die Transit-Aspekte-Tabelle
469
+ console.log('Transit-Aspekte (Transit → Radix):');
470
+ console.log('================================================================================');
471
+ console.log('| Transit | Aspekt | Mit Planet | Orb | Transit Pos | Transit Haus | Geburts Haus | Phase | Exaktes Datum/Uhrzeit |');
472
+ console.log('================================================================================');
473
+
474
+ // Berechne Häuser einmal für alle Planeten
475
+ const birthJulianDay = calculateJulianDayUTC(birthData, getTimezoneOffset(birthData, birthData.location?.timezone || 'Europe/Zurich'));
476
+ const houses = await calculateHouses(birthJulianDay, houseSystem === 'koch' ? 'K' : houseSystem === 'wholesign' ? 'W' : 'G', true);
477
+ const transitDateDisplay = transitDate || getCurrentTimeInTimezone();
478
+
479
+ // Zeige Transit-Aspekte für alle Planeten
480
+ for (const [planetName] of Object.entries(planets)) {
481
+ const transitPlanetData = getAstrologicalData(planetName, transitDateDisplay);
482
+ const transitHouse = getPlanetHouse(parseFloat(transitPlanetData.degreeInSign) + (signs.indexOf(transitPlanetData.sign) * 30), houses.house);
483
+ const transitAspectsData = calculatePersonalTransitAspects(transitDateDisplay, birthData, planetName);
484
+ const transitAspects = transitAspectsData ? transitAspectsData.aspects : [];
485
+ if (transitAspects.length > 0) {
486
+ transitAspects.forEach(aspect => {
487
+ const birthPlanetData = getAstrologicalData(aspect.birthPlanet, birthData);
488
+ const birthHouse = getPlanetHouse(parseFloat(birthPlanetData.degreeInSign) + (signs.indexOf(birthPlanetData.sign) * 30), houses.house);
489
+
490
+ // Bestimme die Aspekt-Phase
491
+ const aspectAngles = {
492
+ 'Konjunktion': 0,
493
+ 'Opposition': 180,
494
+ 'Quadrat': 90,
495
+ 'Trigon': 120,
496
+ 'Sextil': 60
497
+ };
498
+ const targetAngle = aspectAngles[aspect.type];
499
+ const phase = determineAspectPhase(planetName, aspect.birthPlanet, transitDateDisplay, aspect.type, targetAngle);
500
+
501
+ // Berechne das genaue Datum und die Uhrzeit für diesen Aspekt
502
+ const exactDateTime = findExactAspectTime(planetName, aspect.birthPlanet, aspect.type, transitDateDisplay);
503
+ let dateTimeStr = '-';
504
+ if (exactDateTime) {
505
+ dateTimeStr = `${String(exactDateTime.day).padStart(2, '0')}.${String(exactDateTime.month).padStart(2, '0')}.${exactDateTime.year} ${String(exactDateTime.hour).padStart(2, '0')}:${String(exactDateTime.minute).padStart(2, '0')}`;
506
+ } else if (phase === 'separativ') {
507
+ // Für separative Phasen: Suche das letzte exakte Datum in der Vergangenheit
508
+ const lastExactDateTime = findLastExactAspectTime(planetName, aspect.birthPlanet, aspect.type, transitDateDisplay);
509
+ if (lastExactDateTime) {
510
+ dateTimeStr = `${String(lastExactDateTime.day).padStart(2, '0')}.${String(lastExactDateTime.month).padStart(2, '0')}.${lastExactDateTime.year} ${String(lastExactDateTime.hour).padStart(2, '0')}:${String(lastExactDateTime.minute).padStart(2, '0')} (e)`;
511
+ }
512
+ }
513
+
514
+ const transitPlanetFormatted = planetName.charAt(0).toUpperCase() + planetName.slice(1);
515
+ const aspectTypeFormatted = aspect.type.padEnd(11);
516
+ const aspectPlanetFormatted = aspect.birthPlanet.charAt(0).toUpperCase() + aspect.birthPlanet.slice(1);
517
+ const orbFormatted = aspect.orb.padEnd(4);
518
+ const transitPosFormatted = `${transitPlanetData.sign} ${transitPlanetData.degreeInSign}°`;
519
+ const transitHouseFormatted = transitHouse.toString().padEnd(11);
520
+ const birthHouseFormatted = birthHouse.toString().padEnd(11);
521
+ const phaseFormatted = phase === 'separativ' ? 'separativ'.padEnd(11) : phase.padEnd(11);
522
+ const dateTimeFormatted = dateTimeStr.padEnd(22);
523
+
524
+ console.log(`| ${transitPlanetFormatted.padEnd(10)} | ${aspectTypeFormatted} | ${aspectPlanetFormatted.padEnd(10)} | ${orbFormatted}° | ${transitPosFormatted.padEnd(16)} | ${transitHouseFormatted} | ${birthHouseFormatted} | ${phaseFormatted} | ${dateTimeFormatted} |`);
525
+ });
526
+ }
527
+ }
528
+
529
+ console.log('================================================================================');
530
+ console.log(`\nAnalyse-Datum: ${transitDateDisplay.day}.${transitDateDisplay.month}.${transitDateDisplay.year}`);
531
+ console.log(`Geburtsdatum: ${birthData.day}.${birthData.month}.${birthData.year} ${birthData.hour}:${birthData.minute.toString().padStart(2, '0')}`);
532
+ console.log(`Haus-System: ${houseSystem.charAt(0).toUpperCase() + houseSystem.slice(1)} (basierend auf Geburts-ASC)`);
533
+
534
+ }
535
+
536
+ return;
537
+ }
538
+
539
+ // Persönliche Transit-Aspekte anzeigen, falls --transit-aspekte oder --tr Option angegeben
540
+ if (options.transitAspekte || options.tr) {
541
+ // Geburtsdaten sind für Transit-Aspekte erforderlich
542
+ const birthData = getBirthDataFromConfig();
543
+ if (!birthData) {
544
+ console.error('Fehler: Persönliche Transit-Aspekte erfordern Geburtsdaten. Bitte führe --setup aus, um deine Geburtsdaten zu konfigurieren.');
545
+ process.exit(1);
546
+ }
547
+
548
+ // Benutzerdefiniertes Datum verwenden, falls angegeben
549
+ let transitDate = null;
550
+ if (options.d) {
551
+ // Versuche, das Datum als DD.MM.YYYY oder DD.MM.YYYY HH:MM zu parsen
552
+ const dateRegex = /^(\d{1,2})\.(\d{1,2})\.(\d{4})(?:\s+(\d{1,2}):(\d{2}))?$/;
553
+ const match = options.d.match(dateRegex);
554
+
555
+ if (match) {
556
+ const day = parseInt(match[1], 10);
557
+ const month = parseInt(match[2], 10);
558
+ const year = parseInt(match[3], 10);
559
+ const hour = match[4] ? parseInt(match[4], 10) : 12; // Standard: 12 Uhr
560
+ const minute = match[5] ? parseInt(match[5], 10) : 0; // Standard: 0 Minuten
561
+
562
+ // Überprüfe, ob das Datum gültig ist
563
+ const date = new Date(year, month - 1, day, hour, minute);
564
+ if (date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day) {
565
+ transitDate = {
566
+ day: day,
567
+ month: month,
568
+ year: year,
569
+ hour: hour,
570
+ minute: minute
571
+ };
572
+ console.log(`Verwende Transitdatum: ${day}.${month}.${year} ${hour}:${minute.toString().padStart(2, '0')}`);
573
+ } else {
574
+ console.error('Ungültiges Datum:', options.d);
575
+ console.error('💡 Bitte verwende das Format: DD.MM.YYYY oder "DD.MM.YYYY HH:MM" (mit Anführungszeichen für Datum mit Uhrzeit)');
576
+ process.exit(1);
577
+ }
578
+ } else {
579
+ console.error('Ungültiges Datum:', options.d);
580
+ console.error('💡 Bitte verwende das Format: DD.MM.YYYY oder "DD.MM.YYYY HH:MM" (mit Anführungszeichen für Datum mit Uhrzeit)');
581
+ process.exit(1);
582
+ }
583
+ }
584
+
585
+ // Zeige persönliche Transit-Aspekte an
586
+ // Verwende den spezifischen Planeten, falls angegeben, oder alle Planeten
587
+ const targetPlanet = planetArg ? planetArg.toLowerCase() : null;
588
+ showPersonalTransitAspects(transitDate, birthData, targetPlanet);
589
+
590
+ return;
591
+ }
592
+
411
593
  // Aspektfiguren anzeigen, falls --af Option angegeben (ohne Planet erforderlich)
412
594
  if (options.af) {
413
595
  // Geburtsdaten verwenden, falls --ich Option angegeben