klio 1.5.7 → 1.5.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klio",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
4
4
  "description": "A CLI for astrological calculations",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -79,13 +79,22 @@ function getBirthDataFromConfig(userId = null) {
79
79
  const hour = parseInt(timeParts[0]);
80
80
  const minute = parseInt(timeParts[1]);
81
81
 
82
+ const birthLocation = config.birthData.location;
83
+ if (birthLocation && !birthLocation.timezone && config.currentLocation) {
84
+ const latDiff = Math.abs((birthLocation.latitude || 0) - (config.currentLocation.latitude || 0));
85
+ const lonDiff = Math.abs((birthLocation.longitude || 0) - (config.currentLocation.longitude || 0));
86
+ if (latDiff <= 0.1 && lonDiff <= 0.1 && config.currentLocation.timezone) {
87
+ birthLocation.timezone = config.currentLocation.timezone;
88
+ }
89
+ }
90
+
82
91
  return {
83
92
  year: year,
84
93
  month: month,
85
94
  day: day,
86
95
  hour: hour,
87
96
  minute: minute,
88
- location: config.birthData.location
97
+ location: birthLocation
89
98
  };
90
99
  }
91
100
 
@@ -213,13 +222,9 @@ function calculateHouses(julianDay, houseSystem = 'K', useBirthLocation = false,
213
222
  }
214
223
 
215
224
  // Load the configured location data
216
- const configPath = path.join(__dirname, '../../astrocli-config.json');
217
- let config;
225
+ let config = null;
218
226
  try {
219
- if (fs.existsSync(configPath)) {
220
- const configData = fs.readFileSync(configPath, 'utf8');
221
- config = JSON.parse(configData);
222
- }
227
+ config = loadConfig();
223
228
  } catch (error) {
224
229
  console.log('No configuration found, using default location (Berlin)');
225
230
  }
@@ -261,39 +266,28 @@ function calculateHouses(julianDay, houseSystem = 'K', useBirthLocation = false,
261
266
  }
262
267
  reject(result.error);
263
268
  } else {
264
- // The Swiss Ephemeris often returns indices as strings ("1", "2", ...) in the result.house object
265
- // We convert this to a clean 0-based array (0-11) for consistent processing.
269
+
270
+ // The Swiss Ephemeris returns house cusps in result.house, but indexing varies:
271
+ // some implementations return 0-11, others 1-12 (with 0 unused).
272
+ // Normalize to a 0-based array (0-11) for consistent processing.
266
273
  const houseCusps = [];
267
-
268
- // First try to get indices 1 to 12 directly
269
- for (let i = 1; i <= 12; i++) {
270
- const cusp = result.house[i];
271
- if (cusp !== undefined) {
272
- houseCusps.push(cusp);
273
- }
274
- }
275
-
276
- // If we don't have 12 houses (e.g., if the object has different keys),
277
- // try to collect all numeric keys
278
- if (houseCusps.length < 12) {
279
- const keys = Object.keys(result.house).filter(k => !isNaN(k)).sort((a,b) => parseInt(a) - parseInt(b));
280
-
281
- if (keys.length >= 13) {
282
- // Probably index 0 = AC, 1-12 = houses
283
- houseCusps.length = 0;
284
- for (let i = 1; i <= 12; i++) {
285
- const key = keys.find(k => parseInt(k) === i);
286
- if (key !== undefined) {
287
- houseCusps.push(result.house[key]);
288
- }
289
- }
290
- } else if (keys.length === 12) {
291
- // Probably directly 0-11 = houses
292
- houseCusps.length = 0;
293
- for (let i = 0; i < 12; i++) {
294
- houseCusps.push(result.house[keys[i]]);
295
- }
274
+ const numericKeys = Object.keys(result.house)
275
+ .filter(k => !isNaN(k))
276
+ .map(k => parseInt(k, 10))
277
+ .sort((a, b) => a - b);
278
+
279
+ if (numericKeys.length >= 12) {
280
+ const hasOneToTwelve = numericKeys.includes(1) && numericKeys.includes(12);
281
+ const hasZeroToEleven = numericKeys.includes(0) && numericKeys.includes(11) && !numericKeys.includes(12);
282
+ if (hasOneToTwelve && !hasZeroToEleven) {
283
+ for (let i = 1; i <= 12; i++) {
284
+ houseCusps.push(result.house[i]);
285
+ }
286
+ } else {
287
+ for (let i = 0; i < 12; i++) {
288
+ houseCusps.push(result.house[i]);
296
289
  }
290
+ }
297
291
  }
298
292
 
299
293
  // If we still don't have 12 houses (shouldn't happen),
@@ -302,9 +296,22 @@ function calculateHouses(julianDay, houseSystem = 'K', useBirthLocation = false,
302
296
  houseCusps.push(0);
303
297
  }
304
298
 
299
+ let eps = null;
300
+ if (Number.isFinite(swisseph.SE_ECL_NUT) && swisseph.SE_ECL_NUT >= 0) {
301
+ const epsResult = swisseph.swe_calc_ut(julianDay, swisseph.SE_ECL_NUT, swisseph.SEFLG_SWIEPH);
302
+ if (epsResult && !epsResult.error && Number.isFinite(epsResult.longitude)) {
303
+ eps = epsResult.longitude;
304
+ }
305
+ }
306
+
305
307
  const formattedResult = {
306
308
  ...result,
307
- house: houseCusps
309
+ house: houseCusps,
310
+ houseSystem,
311
+ latitude,
312
+ longitude,
313
+ armc: Number.isFinite(result.armc) ? result.armc : null,
314
+ eps: Number.isFinite(result.eps) ? result.eps : eps
308
315
  };
309
316
 
310
317
  resolve(formattedResult);
@@ -347,17 +354,54 @@ function longitudeToSignDegree(longitude) {
347
354
  }
348
355
 
349
356
  // Function to determine the house for a planet
350
- function getPlanetHouse(planetLongitude, houseCusps) {
357
+ function getPlanetHouse(planetLongitude, houseData, planetName = null, planetLatitude = null) {
358
+ const houseCusps = Array.isArray(houseData)
359
+ ? houseData
360
+ : (houseData && Array.isArray(houseData.house) ? houseData.house : []);
361
+ const houseMeta = (!Array.isArray(houseData) && houseData) ? houseData : null;
362
+
351
363
  // Normalize planet longitude to 0-360 range
352
364
  planetLongitude = planetLongitude % 360;
353
365
  if (planetLongitude < 0) planetLongitude += 360;
354
366
 
367
+ // Debug output for Chiron
368
+ const isChiron = planetName && planetName.toLowerCase() === 'chiron';
369
+
370
+ if (
371
+ houseMeta &&
372
+ Number.isFinite(planetLatitude) &&
373
+ Number.isFinite(houseMeta.latitude) &&
374
+ Number.isFinite(houseMeta.armc) &&
375
+ Number.isFinite(houseMeta.eps) &&
376
+ typeof houseMeta.houseSystem === 'string' &&
377
+ swisseph.swe_houses_pos
378
+ ) {
379
+ const housePosResult = swisseph.swe_houses_pos(
380
+ houseMeta.armc,
381
+ houseMeta.latitude,
382
+ houseMeta.eps,
383
+ houseMeta.houseSystem,
384
+ planetLongitude,
385
+ planetLatitude
386
+ );
387
+
388
+ if (housePosResult && !housePosResult.error && Number.isFinite(housePosResult.housePosition)) {
389
+ let house = Math.floor(housePosResult.housePosition);
390
+ if (house < 1) {
391
+ house = 12;
392
+ } else if (house > 12) {
393
+ house = ((house - 1) % 12) + 1;
394
+ }
395
+ return house;
396
+ }
397
+ }
398
+
355
399
  // House cusps are in houseCusps[0] to houseCusps[11]
356
400
  // We need to find between which two house cusps the planet lies
357
401
  for (let i = 0; i < 12; i++) {
358
402
  const currentCusp = houseCusps[i];
359
403
  const nextCusp = houseCusps[(i + 1) % 12];
360
-
404
+
361
405
  // Normalize house cusps to 0-360 range
362
406
  const normalizedCurrentCusp = currentCusp % 360;
363
407
  const normalizedNextCusp = nextCusp % 360;
@@ -376,11 +420,11 @@ function getPlanetHouse(planetLongitude, houseCusps) {
376
420
  }
377
421
  }
378
422
  }
379
-
423
+
380
424
  // Debug: Show house cusps if no house was found
381
425
  console.log('No house found for planet:', planetLongitude);
382
426
  console.log('House cusps:', houseCusps);
383
-
427
+
384
428
  // Fallback: Should not occur
385
429
  return 1;
386
430
  }
@@ -526,6 +570,7 @@ function getAstrologicalData(planetName, customDate = null) {
526
570
  return {
527
571
  planet: planetName,
528
572
  longitude,
573
+ latitude: result.latitude,
529
574
  sign,
530
575
  degreeInSign,
531
576
  dignity,
@@ -1313,7 +1358,7 @@ function detectAspectFigures(dateComponents, houseSystem = null, useBirthData =
1313
1358
  // Add house information if houses were calculated
1314
1359
  if (houses && houses.house) {
1315
1360
  const planetLongitude = parseFloat(planetData.degreeInSign) + (signs.indexOf(planetData.sign) * 30);
1316
- const house = getPlanetHouse(planetLongitude, houses.house);
1361
+ const house = getPlanetHouse(planetLongitude, houses);
1317
1362
  figure.planetDetails[planetName].house = house;
1318
1363
  }
1319
1364
  }
@@ -1443,7 +1488,7 @@ async function calculatePersonalTransits(transitDate = null, birthData = null) {
1443
1488
  const transitResults = {};
1444
1489
  for (const [name, data] of Object.entries(transitPlanets)) {
1445
1490
  const planetLongitude = parseFloat(data.degreeInSign) + (signs.indexOf(data.sign) * 30);
1446
- const house = getPlanetHouse(planetLongitude, houses.house);
1491
+ const house = getPlanetHouse(planetLongitude, houses, name, data.latitude);
1447
1492
 
1448
1493
  transitResults[name] = {
1449
1494
  ...data,
@@ -1461,7 +1506,7 @@ async function calculatePersonalTransits(transitDate = null, birthData = null) {
1461
1506
  }
1462
1507
 
1463
1508
  // Function to calculate personal transit aspects
1464
- function calculatePersonalTransitAspects(transitDate = null, birthData = null, targetPlanet = null) {
1509
+ function calculatePersonalTransitAspects(transitDate = null, birthData = null, targetPlanet = null, useHuberOrbs = true) {
1465
1510
  if (!birthData) {
1466
1511
  birthData = getBirthDataFromConfig();
1467
1512
  if (!birthData) {
@@ -1500,36 +1545,54 @@ function calculatePersonalTransitAspects(transitDate = null, birthData = null, t
1500
1545
 
1501
1546
  // Calculate aspects between transit and birth planets
1502
1547
  const aspects = [];
1503
- const aspectTypes = [
1548
+ // Use the same orb model as other aspect calculations; default to Huber orbs
1549
+ const aspectTypes = useHuberOrbs ? [
1504
1550
  { name: 'Conjunction', angle: 0, orb: 8 },
1505
1551
  { name: 'Opposition', angle: 180, orb: 8 },
1506
1552
  { name: 'Square', angle: 90, orb: 6 },
1507
1553
  { name: 'Trine', angle: 120, orb: 6 },
1508
- { name: 'Sextile', angle: 60, orb: 4 }
1554
+ { name: 'Sextile', angle: 60, orb: 4 },
1555
+ { name: 'Quincunx', angle: 150, orb: 3 }
1556
+ ] : [
1557
+ { name: 'Conjunction', angle: 0, orb: 10 },
1558
+ { name: 'Opposition', angle: 180, orb: 10 },
1559
+ { name: 'Square', angle: 90, orb: 8 },
1560
+ { name: 'Trine', angle: 120, orb: 8 },
1561
+ { name: 'Sextile', angle: 60, orb: 6 },
1562
+ { name: 'Quincunx', angle: 150, orb: 4 }
1509
1563
  ];
1510
1564
 
1511
1565
  // Compare each transit planet with each birth planet
1512
1566
  for (const [transitName, transitLongitude] of Object.entries(transitPlanets)) {
1567
+ // If filtering by target planet, only calculate for that transit planet
1568
+ if (targetPlanet && transitName !== targetPlanet) continue;
1569
+
1513
1570
  for (const [birthName, birthLongitude] of Object.entries(birthPlanets)) {
1514
1571
  // Skip if it's the same planet
1515
1572
  if (transitName === birthName) continue;
1516
1573
 
1517
- // Calculate the angle difference
1518
- const angleDiff = Math.abs(transitLongitude - birthLongitude) % 360;
1519
- const normalizedAngle = Math.min(angleDiff, 360 - angleDiff);
1574
+ // Calculate the angle between the two planets
1575
+ let rawDiff = transitLongitude - birthLongitude;
1576
+ let angleDiff = ((rawDiff % 360) + 360) % 360;
1520
1577
 
1521
- // Check for aspects
1578
+ // Check for aspects using the actual angle
1522
1579
  for (const aspect of aspectTypes) {
1523
- if (Math.abs(normalizedAngle - aspect.angle) <= aspect.orb) {
1580
+ // Check both the angle and its complement (360 - angle)
1581
+ const diff1 = Math.abs(angleDiff - aspect.angle);
1582
+ const diff2 = Math.abs((360 - angleDiff) - aspect.angle);
1583
+ const diff = Math.min(diff1, diff2);
1584
+
1585
+ if (diff <= aspect.orb) {
1524
1586
  aspects.push({
1525
1587
  transitPlanet: transitName,
1526
1588
  birthPlanet: birthName,
1527
1589
  type: aspect.name,
1528
- angle: normalizedAngle.toFixed(2),
1529
- orb: Math.abs(normalizedAngle - aspect.angle).toFixed(2),
1590
+ angle: angleDiff.toFixed(2),
1591
+ orb: diff.toFixed(2),
1530
1592
  transitLongitude: transitLongitude,
1531
1593
  birthLongitude: birthLongitude
1532
1594
  });
1595
+ break; // Only match one aspect per planet pair
1533
1596
  }
1534
1597
  }
1535
1598
  }
@@ -1548,8 +1611,8 @@ function calculatePersonalTransitAspects(transitDate = null, birthData = null, t
1548
1611
  }
1549
1612
 
1550
1613
  // Function to display personal transit aspects
1551
- function showPersonalTransitAspects(transitDate = null, birthData = null, targetPlanet = null) {
1552
- const aspectData = calculatePersonalTransitAspects(transitDate, birthData, targetPlanet);
1614
+ function showPersonalTransitAspects(transitDate = null, birthData = null, targetPlanet = null, useHuberOrbs = true) {
1615
+ const aspectData = calculatePersonalTransitAspects(transitDate, birthData, targetPlanet, useHuberOrbs);
1553
1616
 
1554
1617
  if (!aspectData || aspectData.aspects.length === 0) {
1555
1618
  console.log('No personal transit aspects found.');
@@ -1557,7 +1620,7 @@ function showPersonalTransitAspects(transitDate = null, birthData = null, target
1557
1620
  }
1558
1621
 
1559
1622
  const transitDateDisplay = transitDate || getCurrentTimeInTimezone();
1560
- console.log(`Personal Transit Aspects (${transitDateDisplay.day}.${transitDateDisplay.month}.${transitDateDisplay.year}):`);
1623
+ console.log(`Personal Transit Aspects (${transitDateDisplay.day}.${transitDateDisplay.month}.${transitDateDisplay.year}) [${(aspectData && aspectData.aspects.length>0) ? (useHuberOrbs ? 'Huber orbs' : 'Standard orbs') : ''}]:`);
1561
1624
  console.log('================================================================================');
1562
1625
  console.log('| Transit | Birth | Aspect | Orb | Transit Pos | Birth Pos |');
1563
1626
  console.log('================================================================================');
@@ -1617,12 +1680,12 @@ async function showCombinedAnalysis(planetName, transitDate = null, birthData =
1617
1680
  // Calculate current planet positions (Transit)
1618
1681
  const transitPlanetData = getAstrologicalData(planetName, transitDate);
1619
1682
  const transitLongitude = transitPlanetData.longitude;
1620
- const transitHouse = getPlanetHouse(transitLongitude, houses.house);
1683
+ const transitHouse = getPlanetHouse(transitLongitude, houses, planetName, transitPlanetData.latitude);
1621
1684
 
1622
1685
  // Calculate birth planet positions (Radix)
1623
1686
  const birthPlanetData = getAstrologicalData(planetName, birthData);
1624
1687
  const birthLongitude = birthPlanetData.longitude;
1625
- const birthHouse = getPlanetHouse(birthLongitude, houses.house);
1688
+ const birthHouse = getPlanetHouse(birthLongitude, houses, planetName, birthPlanetData.latitude);
1626
1689
 
1627
1690
  // Calculate birth aspects for the planet
1628
1691
  const birthAspects = calculatePlanetAspects(planetName, birthData, true);
@@ -1651,7 +1714,8 @@ async function showCombinedAnalysis(planetName, transitDate = null, birthData =
1651
1714
  console.log('--------------------------------------------------------------------------------');
1652
1715
  birthAspects.forEach(aspect => {
1653
1716
  const aspectPlanetData = getAstrologicalData(aspect.planet, birthData);
1654
- const aspectHouse = getPlanetHouse(parseFloat(aspectPlanetData.degreeInSign) + (signs.indexOf(aspectPlanetData.sign) * 30), houses.house);
1717
+ const aspectLongitude = parseFloat(aspectPlanetData.degreeInSign) + (signs.indexOf(aspectPlanetData.sign) * 30);
1718
+ const aspectHouse = getPlanetHouse(aspectLongitude, houses);
1655
1719
  console.log(`${aspect.type.padEnd(12)} with ${aspect.planet.padEnd(8)} (${aspectPlanetData.sign} ${aspectPlanetData.degreeInSign}° House ${aspectHouse}) - Orb: ${aspect.orb}°`);
1656
1720
  });
1657
1721
  console.log('');
@@ -1663,7 +1727,8 @@ async function showCombinedAnalysis(planetName, transitDate = null, birthData =
1663
1727
  console.log('--------------------------------------------------------------------------------');
1664
1728
  transitAspects.forEach(aspect => {
1665
1729
  const birthPlanetData = getAstrologicalData(aspect.birthPlanet, birthData);
1666
- const birthHouse = getPlanetHouse(parseFloat(birthPlanetData.degreeInSign) + (signs.indexOf(birthPlanetData.sign) * 30), houses.house);
1730
+ const birthLongitude = parseFloat(birthPlanetData.degreeInSign) + (signs.indexOf(birthPlanetData.sign) * 30);
1731
+ const birthHouse = getPlanetHouse(birthLongitude, houses);
1667
1732
  console.log(`${aspect.type.padEnd(12)} with ${aspect.birthPlanet.padEnd(8)} (${birthPlanetData.sign} ${birthPlanetData.degreeInSign}° House ${birthHouse}) - Orb: ${aspect.orb}°`);
1668
1733
  });
1669
1734
  console.log('');
@@ -2303,7 +2368,7 @@ function analyzeCSVWithDatetime(filePath, planetName = 'moon', houseSystem = 'ko
2303
2368
  calculateHouses(julianDay, getHouseSystemCode(houseSystem), false)
2304
2369
  .then(houses => {
2305
2370
  const planetLongitude = parseFloat(astroData.degreeInSign) + (signs.indexOf(astroData.sign) * 30);
2306
- const house = getPlanetHouse(planetLongitude, houses.house);
2371
+ const house = getPlanetHouse(planetLongitude, houses, planetName, astroData.latitude);
2307
2372
 
2308
2373
  // Calculate aspects if requested
2309
2374
  let aspects = [];
@@ -2547,7 +2612,7 @@ function analyzeCSVWithDatetime(filePath, planetName = 'moon', houseSystem = 'ko
2547
2612
  calculateHouses(julianDay, getHouseSystemCode(houseSystem), false)
2548
2613
  .then(houses => {
2549
2614
  const planetLongitude = parseFloat(astroData.degreeInSign) + (signs.indexOf(astroData.sign) * 30);
2550
- const house = getPlanetHouse(planetLongitude, houses.house);
2615
+ const house = getPlanetHouse(planetLongitude, houses, planetName, astroData.latitude);
2551
2616
 
2552
2617
  // Berechne Aspekte, falls angefordert
2553
2618
  let aspects = [];
@@ -11,6 +11,7 @@ const SE_GREG_CAL = nativeSwisseph ? nativeSwisseph.SE_GREG_CAL : 1;
11
11
  const SEFLG_SWIEPH = nativeSwisseph ? nativeSwisseph.SEFLG_SWIEPH : 2;
12
12
  const SEFLG_SPEED = nativeSwisseph ? nativeSwisseph.SEFLG_SPEED : 256;
13
13
  const SEFLG_MOSEPH = nativeSwisseph ? nativeSwisseph.SEFLG_MOSEPH : 4;
14
+ const SE_ECL_NUT = nativeSwisseph ? nativeSwisseph.SE_ECL_NUT : -1;
14
15
 
15
16
  let wasmModule = null;
16
17
  let wasmGet = null;
@@ -19,10 +20,17 @@ let wasmReadyPromise = null;
19
20
  const planetCache = new Map();
20
21
  const houseCache = new Map();
21
22
 
23
+ function isWasmAllowed() {
24
+ return process.env.KLIO_ALLOW_WASM === '1';
25
+ }
26
+
22
27
  function ensureReady() {
23
28
  if (nativeSwisseph) {
24
29
  return;
25
30
  }
31
+ if (!isWasmAllowed()) {
32
+ throw new Error('Native swisseph is required. Set KLIO_ALLOW_WASM=1 to enable WASM fallback.');
33
+ }
26
34
  if (!wasmModule || !wasmGet) {
27
35
  throw new Error('Sweph WASM is not initialized. Call initialize() before use.');
28
36
  }
@@ -32,6 +40,9 @@ async function initialize() {
32
40
  if (nativeSwisseph) {
33
41
  return;
34
42
  }
43
+ if (!isWasmAllowed()) {
44
+ throw new Error('Native swisseph is required. Set KLIO_ALLOW_WASM=1 to enable WASM fallback.');
45
+ }
35
46
  if (!wasmReadyPromise) {
36
47
  wasmReadyPromise = loadSwephWasmModule().then((moduleInstance) => {
37
48
  wasmModule = moduleInstance;
@@ -258,6 +269,17 @@ function swe_houses(julianDay, latitude, longitude, houseSystem, callback) {
258
269
  return result;
259
270
  }
260
271
 
272
+ function swe_houses_pos(armc, latitude, eps, houseSystem, longitude, planetLatitude, callback) {
273
+ if (nativeSwisseph && nativeSwisseph.swe_houses_pos) {
274
+ return nativeSwisseph.swe_houses_pos(armc, latitude, eps, houseSystem, longitude, planetLatitude, callback);
275
+ }
276
+ const fallback = { error: 'swe_houses_pos not available' };
277
+ if (typeof callback === 'function') {
278
+ callback(fallback);
279
+ }
280
+ return fallback;
281
+ }
282
+
261
283
  function swe_set_ephe_path() {
262
284
  if (nativeSwisseph && nativeSwisseph.swe_set_ephe_path) {
263
285
  return nativeSwisseph.swe_set_ephe_path.apply(nativeSwisseph, arguments);
@@ -270,10 +292,12 @@ module.exports = {
270
292
  SEFLG_SWIEPH,
271
293
  SEFLG_SPEED,
272
294
  SEFLG_MOSEPH,
295
+ SE_ECL_NUT,
273
296
  initialize,
274
297
  swe_set_ephe_path,
275
298
  swe_calc_ut,
276
299
  swe_julday,
277
300
  swe_revjul,
278
- swe_houses
301
+ swe_houses,
302
+ swe_houses_pos
279
303
  };
package/src/cli/cli.js CHANGED
@@ -269,7 +269,7 @@ const createAstrologicalNote = async (planetArg, planet2Arg, options, customDate
269
269
  const julianDay = getJulianDay(currentDate, shouldUseBirthData(options));
270
270
  const houses = await calculateHouses(julianDay, getHouseSystemCode(houseSystem), shouldUseBirthData(options));
271
271
  const planetLongitude = parseFloat(planetData.degreeInSign) + (signs.indexOf(planetData.sign) * 30);
272
- const house = getPlanetHouse(planetLongitude, houses.house);
272
+ const house = getPlanetHouse(planetLongitude, houses, planetArg, planetData.latitude);
273
273
  noteData.house = house;
274
274
  noteData.astrologicalSituation += ` in house ${house}`;
275
275
  }
@@ -881,19 +881,22 @@ program
881
881
  const allAspects = [];
882
882
  for (const [planetName] of Object.entries(planets)) {
883
883
  const transitPlanetData = getAstrologicalData(planetName, transitDateDisplay);
884
- const transitHouse = getPlanetHouse(parseFloat(transitPlanetData.degreeInSign) + (signs.indexOf(transitPlanetData.sign) * 30), houses.house);
885
- const transitAspectsData = calculatePersonalTransitAspects(transitDateDisplay, birthData, planetName);
884
+ const transitLongitude = parseFloat(transitPlanetData.degreeInSign) + (signs.indexOf(transitPlanetData.sign) * 30);
885
+ const transitHouse = getPlanetHouse(transitLongitude, houses, planetName, transitPlanetData.latitude);
886
+ const transitAspectsData = calculatePersonalTransitAspects(transitDateDisplay, birthData, planetName, true);
886
887
  const transitAspects = transitAspectsData ? transitAspectsData.aspects : [];
887
888
 
888
889
  // Add planet data to each aspect for later display
889
890
  transitAspects.forEach(aspect => {
891
+ const birthPlanetData = getAstrologicalData(aspect.birthPlanet, birthData);
892
+ const birthLongitude = parseFloat(birthPlanetData.degreeInSign) + (signs.indexOf(birthPlanetData.sign) * 30);
890
893
  allAspects.push({
891
894
  planetName: planetName,
892
895
  transitPlanetData: transitPlanetData,
893
896
  transitHouse: transitHouse,
894
897
  aspect: aspect,
895
- birthPlanetData: getAstrologicalData(aspect.birthPlanet, birthData),
896
- birthHouse: getPlanetHouse(parseFloat(getAstrologicalData(aspect.birthPlanet, birthData).degreeInSign) + (signs.indexOf(getAstrologicalData(aspect.birthPlanet, birthData).sign) * 30), houses.house)
898
+ birthPlanetData: birthPlanetData,
899
+ birthHouse: getPlanetHouse(birthLongitude, houses, aspect.birthPlanet, birthPlanetData.latitude)
897
900
  });
898
901
  });
899
902
  }
@@ -999,13 +1002,13 @@ program
999
1002
  // Show personal transit aspects
1000
1003
  // Use the specific planet if specified, or all planets
1001
1004
  const targetPlanet = planetArg ? planetArg.toLowerCase() : null;
1002
- showPersonalTransitAspects(transitDate, birthData, targetPlanet);
1005
+ showPersonalTransitAspects(transitDate, birthData, targetPlanet, true);
1003
1006
 
1004
1007
  // Handle AI request for personal transit aspects
1005
1008
  if (options.p) {
1006
1009
  // Get the transit aspects data for AI
1007
1010
  const { calculatePersonalTransitAspects } = require('../astrology/astrologyService');
1008
- const transitAspectsData = calculatePersonalTransitAspects(transitDate, birthData, targetPlanet);
1011
+ const transitAspectsData = calculatePersonalTransitAspects(transitDate, birthData, targetPlanet, true);
1009
1012
  const transitAspects = transitAspectsData ? transitAspectsData.aspects : [];
1010
1013
 
1011
1014
  const aiData = {
@@ -1664,7 +1667,7 @@ program
1664
1667
  let house = 'N/A';
1665
1668
  if (houses) {
1666
1669
  const planetLongitude = parseFloat(data.degreeInSign) + (signs.indexOf(data.sign) * 30);
1667
- house = getPlanetHouse(planetLongitude, houses.house);
1670
+ house = getPlanetHouse(planetLongitude, houses, name, data.latitude);
1668
1671
  }
1669
1672
 
1670
1673
  const planetNameFormatted = name.charAt(0).toUpperCase() + name.slice(1);
@@ -1732,7 +1735,7 @@ program
1732
1735
  let house = 'N/A';
1733
1736
  if (houses) {
1734
1737
  const planetLongitude = parseFloat(data.degreeInSign) + (signs.indexOf(data.sign) * 30);
1735
- house = getPlanetHouse(planetLongitude, houses.house);
1738
+ house = getPlanetHouse(planetLongitude, houses, name, data.latitude);
1736
1739
  }
1737
1740
  allPlanetData[name] = {
1738
1741
  sign: data.sign,
@@ -2476,7 +2479,8 @@ program
2476
2479
  houses = await calculateHouses(julianDay, getHouseSystemCode(houseSystem), useBirthLocation);
2477
2480
 
2478
2481
  // Determine the house of the planet
2479
- const planetHouse = getPlanetHouse(parseFloat(data.degreeInSign) + (signs.indexOf(data.sign) * 30), houses.house);
2482
+ const planetLongitude = parseFloat(data.degreeInSign) + (signs.indexOf(data.sign) * 30);
2483
+ const planetHouse = getPlanetHouse(planetLongitude, houses, planet, data.latitude);
2480
2484
  houseInfo = {
2481
2485
  house: planetHouse,
2482
2486
  houseSystem: options.hs
@@ -3021,7 +3025,8 @@ program
3021
3025
  }
3022
3026
 
3023
3027
  // Determine the planet's house
3024
- const planetHouse = getPlanetHouse(parseFloat(data.degreeInSign) + (signs.indexOf(data.sign) * 30), houses.house);
3028
+ const planetLongitude = parseFloat(data.degreeInSign) + (signs.indexOf(data.sign) * 30);
3029
+ const planetHouse = getPlanetHouse(planetLongitude, houses, data.planet, data.latitude);
3025
3030
  const planetNameCapitalized = data.planet.charAt(0).toUpperCase() + data.planet.slice(1);
3026
3031
  console.log(`${planetNameCapitalized} is in house ${planetHouse}`);
3027
3032
  console.log();
@@ -887,16 +887,18 @@ class CLIService {
887
887
  // Function to calculate Julian Day in UTC for house calculation
888
888
  const getJulianDayUTCForHouses = () => {
889
889
  let timezoneOffsetMinutes = 0;
890
-
890
+
891
891
  if (birthData && birthData.location) {
892
- timezoneOffsetMinutes = getTimezoneOffset(birthData, birthData.location.timezone || 'Europe/Zurich');
892
+ // Use the natal location's timezone, but with the current date (or --d date)
893
+ timezoneOffsetMinutes = getTimezoneOffset(customDate, birthData.location.timezone || 'Europe/Zurich');
893
894
  } else if (config && config.currentLocation && config.currentLocation.timezone) {
894
895
  timezoneOffsetMinutes = getTimezoneOffset(customDate, config.currentLocation.timezone);
895
896
  } else {
896
897
  timezoneOffsetMinutes = -new Date().getTimezoneOffset();
897
898
  }
898
-
899
- return calculateJulianDayUTC(birthData ? birthData : customDate, timezoneOffsetMinutes);
899
+
900
+ // Always use customDate (current or --d date), not birthData
901
+ return calculateJulianDayUTC(customDate, timezoneOffsetMinutes);
900
902
  };
901
903
 
902
904
  // Calculate houses if house system is specified
@@ -921,12 +923,12 @@ class CLIService {
921
923
  // Calculate positions of all planets
922
924
  for (const [name, planetId] of Object.entries(planets)) {
923
925
  const data = getAstrologicalData(name, customDate);
924
-
926
+
925
927
  // Determine the house if houses were calculated
926
928
  let house = 'N/A';
927
929
  if (houses) {
928
- const planetLongitude = parseFloat(data.degreeInSign) + (signs.indexOf(data.sign) * 30);
929
- house = getPlanetHouse(planetLongitude, houses.house);
930
+ // Use the actual longitude value directly (not reconstructed from sign+degree)
931
+ house = getPlanetHouse(data.longitude, houses, name, data.latitude);
930
932
  }
931
933
 
932
934
  const planetNameFormatted = name.charAt(0).toUpperCase() + name.slice(1);
@@ -735,7 +735,8 @@ async function performSetup(userId = null) {
735
735
  name: birthGeoData.name,
736
736
  country: birthGeoData.country,
737
737
  latitude: birthGeoData.latitude,
738
- longitude: birthGeoData.longitude
738
+ longitude: birthGeoData.longitude,
739
+ timezone: birthGeoData.timezone
739
740
  } : null
740
741
  },
741
742
  aiConfiguration: aiConfig,
@@ -209,6 +209,7 @@ const command = rawCommand.startsWith('klio ') ? rawCommand.slice(5).trim() : ra
209
209
 
210
210
  process.env.KLIO_CAPTURE_ONLY = '1';
211
211
  process.env.KLIO_CONFIG_PATH = '/src/.astrocli/config.json';
212
+ process.env.KLIO_ALLOW_WASM = '1';
212
213
  try {
213
214
  const configText = fs.readFileSync(process.env.KLIO_CONFIG_PATH, 'utf8');
214
215
  if (configText) {