thoth-cli 0.2.15 → 0.2.17

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.
Binary file
package/dist/bin.js CHANGED
@@ -3,30 +3,38 @@ import {
3
3
  chart,
4
4
  composite,
5
5
  ephemeris,
6
+ ephemerisMulti,
6
7
  ephemerisRange,
7
8
  formatChart,
8
9
  formatComposite,
9
10
  formatEphemeris,
11
+ formatEphemerisMulti,
10
12
  formatEphemerisRange,
11
13
  formatHorary,
12
14
  formatLunarReturn,
13
15
  formatMoon,
16
+ formatMoonExtended,
14
17
  formatProgressions,
18
+ formatScore,
15
19
  formatSolarArc,
16
20
  formatSolarReturn,
17
21
  formatSynastry,
22
+ formatTransitScan,
18
23
  formatTransits,
19
24
  horary,
20
25
  isError,
21
26
  lunarReturn,
22
27
  moon,
28
+ moonExtended,
23
29
  progressions,
30
+ score,
24
31
  solarArc,
25
32
  solarReturn,
26
33
  synastry,
27
34
  transit,
35
+ transitScan,
28
36
  version
29
- } from "./chunk-SURUD7BV.js";
37
+ } from "./chunk-QND56LGZ.js";
30
38
 
31
39
  // src/bin.ts
32
40
  import { Command } from "commander";
@@ -88,7 +96,7 @@ EPHEMERIS & MOON
88
96
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
89
97
  REFERENCE
90
98
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
91
- thoth key # full symbol reference`).version("0.2.15");
99
+ thoth key # full symbol reference`).version("0.2.17");
92
100
  program.command("chart").description("Calculate a natal chart").requiredOption("--date <date>", "Birth date (YYYY-MM-DD)").requiredOption("--time <time>", "Birth time (HH:MM)").option("--lat <lat>", "Latitude", parseFloat).option("--lng <lng>", "Longitude", parseFloat).option("--city <city>", "City name").option("--nation <nation>", "Country code", "US").option("--name <name>", "Name", "Subject").option("--json", "Output raw JSON").option("--svg", "Output SVG chart").option("--svg-file <path>", "Save SVG to file").action(async (options) => {
93
101
  if (!options.city && (!options.lat || !options.lng)) {
94
102
  console.error(chalk.red("Error: Must provide either --city or both --lat and --lng"));
@@ -664,7 +672,134 @@ program.command("key").description("Symbol reference guide").action(() => {
664
672
  console.log(` ${chalk.bold("Fall")} Planet opposite exaltation. Weakened. ${chalk.dim("e.g., \u2609 in Libra")}`);
665
673
  console.log("");
666
674
  });
675
+ program.command("score").description("Calculate relationship compatibility score").requiredOption("--date1 <date>", "Person 1 birth date (YYYY-MM-DD)").requiredOption("--time1 <time>", "Person 1 birth time (HH:MM)").option("--city1 <city>", "Person 1 city").option("--nation1 <nation>", "Person 1 country code", "US").option("--lat1 <lat>", "Person 1 latitude", parseFloat).option("--lng1 <lng>", "Person 1 longitude", parseFloat).option("--name1 <name>", "Person 1 name", "Person 1").requiredOption("--date2 <date>", "Person 2 birth date (YYYY-MM-DD)").requiredOption("--time2 <time>", "Person 2 birth time (HH:MM)").option("--city2 <city>", "Person 2 city").option("--nation2 <nation>", "Person 2 country code", "US").option("--lat2 <lat>", "Person 2 latitude", parseFloat).option("--lng2 <lng>", "Person 2 longitude", parseFloat).option("--name2 <name>", "Person 2 name", "Person 2").option("--json", "Output raw JSON").action(async (options) => {
676
+ const [year1, month1, day1] = options.date1.split("-").map(Number);
677
+ const [hour1, minute1] = options.time1.split(":").map(Number);
678
+ const [year2, month2, day2] = options.date2.split("-").map(Number);
679
+ const [hour2, minute2] = options.time2.split(":").map(Number);
680
+ const spinner = ora("Calculating compatibility...").start();
681
+ const result = await score({
682
+ year1,
683
+ month1,
684
+ day1,
685
+ hour1,
686
+ minute1,
687
+ city1: options.city1,
688
+ nation1: options.nation1,
689
+ lat1: options.lat1,
690
+ lng1: options.lng1,
691
+ name1: options.name1,
692
+ year2,
693
+ month2,
694
+ day2,
695
+ hour2,
696
+ minute2,
697
+ city2: options.city2,
698
+ nation2: options.nation2,
699
+ lat2: options.lat2,
700
+ lng2: options.lng2,
701
+ name2: options.name2
702
+ });
703
+ spinner.stop();
704
+ if (isError(result)) {
705
+ console.error(chalk.red("Error: " + result.error));
706
+ process.exit(1);
707
+ }
708
+ if (options.json) {
709
+ console.log(JSON.stringify(result, null, 2));
710
+ } else {
711
+ console.log(formatScore(result));
712
+ }
713
+ });
714
+ program.command("moon-extended").description("Get detailed moon data with eclipses and sunrise/sunset").option("--date <date>", "Date (YYYY-MM-DD, default: today)").option("--lat <lat>", "Latitude", parseFloat, 40.7128).option("--lng <lng>", "Longitude", parseFloat, -74.006).option("--tz <tz>", "Timezone", "America/New_York").option("--json", "Output raw JSON").action(async (options) => {
715
+ let year, month, day;
716
+ if (options.date) {
717
+ [year, month, day] = options.date.split("-").map(Number);
718
+ }
719
+ const spinner = ora("Getting moon details...").start();
720
+ const result = await moonExtended({
721
+ year,
722
+ month,
723
+ day,
724
+ lat: options.lat,
725
+ lng: options.lng,
726
+ tz: options.tz
727
+ });
728
+ spinner.stop();
729
+ if (isError(result)) {
730
+ console.error(chalk.red("Error: " + result.error));
731
+ process.exit(1);
732
+ }
733
+ if (options.json) {
734
+ console.log(JSON.stringify(result, null, 2));
735
+ } else {
736
+ console.log(formatMoonExtended(result));
737
+ }
738
+ });
739
+ program.command("transit-scan").description("Scan for transit aspects over a date range").requiredOption("--natal-date <date>", "Natal birth date (YYYY-MM-DD)").requiredOption("--natal-time <time>", "Natal birth time (HH:MM)").option("--city <city>", "Natal city").option("--nation <nation>", "Country code", "US").option("--lat <lat>", "Natal latitude", parseFloat).option("--lng <lng>", "Natal longitude", parseFloat).requiredOption("--from <date>", "Start date (YYYY-MM-DD)").requiredOption("--to <date>", "End date (YYYY-MM-DD)").option("--orb <orb>", "Aspect orb in degrees", parseFloat, 1).option("--step <step>", "Step: day or week", "day").option("--json", "Output raw JSON").action(async (options) => {
740
+ const [natalYear, natalMonth, natalDay] = options.natalDate.split("-").map(Number);
741
+ const [natalHour, natalMinute] = options.natalTime.split(":").map(Number);
742
+ const [startYear, startMonth, startDay] = options.from.split("-").map(Number);
743
+ const [endYear, endMonth, endDay] = options.to.split("-").map(Number);
744
+ const spinner = ora("Scanning transits...").start();
745
+ const result = await transitScan({
746
+ natalYear,
747
+ natalMonth,
748
+ natalDay,
749
+ natalHour,
750
+ natalMinute,
751
+ natalCity: options.city,
752
+ nation: options.nation,
753
+ natalLat: options.lat,
754
+ natalLng: options.lng,
755
+ startYear,
756
+ startMonth,
757
+ startDay,
758
+ endYear,
759
+ endMonth,
760
+ endDay,
761
+ orb: options.orb,
762
+ step: options.step
763
+ });
764
+ spinner.stop();
765
+ if (isError(result)) {
766
+ console.error(chalk.red("Error: " + result.error));
767
+ process.exit(1);
768
+ }
769
+ if (options.json) {
770
+ console.log(JSON.stringify(result, null, 2));
771
+ } else {
772
+ console.log(formatTransitScan(result));
773
+ }
774
+ });
775
+ program.command("ephemeris-multi").description("Get ephemeris for multiple bodies over a date range").option("--bodies <bodies>", "Comma-separated bodies", "sun,moon,mercury,venus,mars,jupiter,saturn").requiredOption("--from <date>", "Start date (YYYY-MM-DD)").requiredOption("--to <date>", "End date (YYYY-MM-DD)").option("--step <step>", "Step: hour, day, week, month", "day").option("--lat <lat>", "Latitude", parseFloat).option("--lng <lng>", "Longitude", parseFloat).option("--json", "Output raw JSON").action(async (options) => {
776
+ const [startYear, startMonth, startDay] = options.from.split("-").map(Number);
777
+ const [endYear, endMonth, endDay] = options.to.split("-").map(Number);
778
+ const spinner = ora("Getting ephemeris data...").start();
779
+ const result = await ephemerisMulti({
780
+ bodies: options.bodies,
781
+ startYear,
782
+ startMonth,
783
+ startDay,
784
+ endYear,
785
+ endMonth,
786
+ endDay,
787
+ step: options.step,
788
+ lat: options.lat,
789
+ lng: options.lng
790
+ });
791
+ spinner.stop();
792
+ if (isError(result)) {
793
+ console.error(chalk.red("Error: " + result.error));
794
+ process.exit(1);
795
+ }
796
+ if (options.json) {
797
+ console.log(JSON.stringify(result, null, 2));
798
+ } else {
799
+ console.log(formatEphemerisMulti(result));
800
+ }
801
+ });
667
802
  console.log(chalk.dim(""));
668
- console.log(chalk.yellow(" \u{1315D}") + chalk.dim(" thoth-cli v0.2.15"));
803
+ console.log(chalk.yellow(" \u{1315D}") + chalk.dim(" thoth-cli v0.2.17"));
669
804
  console.log(chalk.dim(""));
670
805
  program.parse();
@@ -400,6 +400,120 @@ async function horary(options) {
400
400
  async function version() {
401
401
  return execute("version", []);
402
402
  }
403
+ async function score(options) {
404
+ const args = [
405
+ "--year1",
406
+ String(options.year1),
407
+ "--month1",
408
+ String(options.month1),
409
+ "--day1",
410
+ String(options.day1),
411
+ "--hour1",
412
+ String(options.hour1 ?? 12),
413
+ "--minute1",
414
+ String(options.minute1 ?? 0),
415
+ "--name1",
416
+ options.name1 ?? "Person 1",
417
+ "--year2",
418
+ String(options.year2),
419
+ "--month2",
420
+ String(options.month2),
421
+ "--day2",
422
+ String(options.day2),
423
+ "--hour2",
424
+ String(options.hour2 ?? 12),
425
+ "--minute2",
426
+ String(options.minute2 ?? 0),
427
+ "--name2",
428
+ options.name2 ?? "Person 2"
429
+ ];
430
+ if (options.city1) {
431
+ args.push("--city1", options.city1);
432
+ args.push("--nation1", options.nation1 ?? "US");
433
+ } else if (options.lat1 !== void 0 && options.lng1 !== void 0) {
434
+ args.push("--lat1", String(options.lat1));
435
+ args.push("--lng1", String(options.lng1));
436
+ }
437
+ if (options.city2) {
438
+ args.push("--city2", options.city2);
439
+ args.push("--nation2", options.nation2 ?? "US");
440
+ } else if (options.lat2 !== void 0 && options.lng2 !== void 0) {
441
+ args.push("--lat2", String(options.lat2));
442
+ args.push("--lng2", String(options.lng2));
443
+ }
444
+ return execute("score", args);
445
+ }
446
+ async function moonExtended(options) {
447
+ const args = [];
448
+ if (options.year) args.push("--year", String(options.year));
449
+ if (options.month) args.push("--month", String(options.month));
450
+ if (options.day) args.push("--day", String(options.day));
451
+ if (options.lat !== void 0) args.push("--lat", String(options.lat));
452
+ if (options.lng !== void 0) args.push("--lng", String(options.lng));
453
+ if (options.tz) args.push("--tz", options.tz);
454
+ return execute("moon-extended", args);
455
+ }
456
+ async function transitScan(options) {
457
+ const args = [
458
+ "--natal-year",
459
+ String(options.natalYear),
460
+ "--natal-month",
461
+ String(options.natalMonth),
462
+ "--natal-day",
463
+ String(options.natalDay),
464
+ "--natal-hour",
465
+ String(options.natalHour ?? 12),
466
+ "--natal-minute",
467
+ String(options.natalMinute ?? 0),
468
+ "--start-year",
469
+ String(options.startYear),
470
+ "--start-month",
471
+ String(options.startMonth ?? 1),
472
+ "--start-day",
473
+ String(options.startDay ?? 1),
474
+ "--end-year",
475
+ String(options.endYear),
476
+ "--end-month",
477
+ String(options.endMonth ?? 12),
478
+ "--end-day",
479
+ String(options.endDay ?? 28),
480
+ "--orb",
481
+ String(options.orb ?? 1),
482
+ "--step",
483
+ options.step ?? "day"
484
+ ];
485
+ if (options.natalCity) {
486
+ args.push("--natal-city", options.natalCity);
487
+ args.push("--nation", options.nation ?? "US");
488
+ } else if (options.natalLat !== void 0 && options.natalLng !== void 0) {
489
+ args.push("--natal-lat", String(options.natalLat));
490
+ args.push("--natal-lng", String(options.natalLng));
491
+ }
492
+ return execute("transit-scan", args);
493
+ }
494
+ async function ephemerisMulti(options) {
495
+ const args = [
496
+ "--bodies",
497
+ options.bodies ?? "sun,moon,mercury,venus,mars,jupiter,saturn",
498
+ "--start-year",
499
+ String(options.startYear),
500
+ "--start-month",
501
+ String(options.startMonth ?? 1),
502
+ "--start-day",
503
+ String(options.startDay ?? 1),
504
+ "--end-year",
505
+ String(options.endYear),
506
+ "--end-month",
507
+ String(options.endMonth ?? 12),
508
+ "--end-day",
509
+ String(options.endDay ?? 28),
510
+ "--step",
511
+ options.step ?? "day"
512
+ ];
513
+ if (options.lat !== void 0) args.push("--lat", String(options.lat));
514
+ if (options.lng !== void 0) args.push("--lng", String(options.lng));
515
+ return execute("ephemeris-multi", args);
516
+ }
403
517
 
404
518
  // src/lib/format.ts
405
519
  import chalk from "chalk";
@@ -1171,6 +1285,155 @@ function formatHorary(result) {
1171
1285
  lines.push("");
1172
1286
  return lines.join("\n");
1173
1287
  }
1288
+ function formatScore(result) {
1289
+ const lines = [];
1290
+ lines.push("");
1291
+ lines.push(chalk.bold.magenta("\u{1F495} Relationship Compatibility Score"));
1292
+ lines.push("");
1293
+ const scoreValue = result.score.value;
1294
+ const scoreDesc = result.score.description;
1295
+ const scoreColor = scoreValue >= 15 ? chalk.green : scoreValue >= 8 ? chalk.yellow : chalk.red;
1296
+ lines.push(` ${chalk.bold("Score:")} ${scoreColor(scoreValue)} / 20 (${scoreDesc})`);
1297
+ if (result.score.is_destiny_sign) {
1298
+ lines.push(` ${chalk.magenta("\u2728 Destiny Sign Connection!")}`);
1299
+ }
1300
+ lines.push("");
1301
+ lines.push(chalk.bold.cyan("\u2500\u2500 COMPARISON \u2500\u2500"));
1302
+ const p1 = result.person1;
1303
+ const p2 = result.person2;
1304
+ lines.push(` ${chalk.bold(p1.name)}: ${getZodiacSymbol(p1.sun)} ${p1.sun} Sun, ${getZodiacSymbol(p1.moon)} ${p1.moon} Moon`);
1305
+ lines.push(` ${chalk.bold(p2.name)}: ${getZodiacSymbol(p2.sun)} ${p2.sun} Sun, ${getZodiacSymbol(p2.moon)} ${p2.moon} Moon`);
1306
+ lines.push("");
1307
+ if (result.breakdown && result.breakdown.length > 0) {
1308
+ lines.push(chalk.bold.cyan("\u2500\u2500 SCORE BREAKDOWN \u2500\u2500"));
1309
+ for (const b of result.breakdown) {
1310
+ const pointColor = b.points > 0 ? chalk.green : chalk.red;
1311
+ lines.push(` ${pointColor(`+${b.points}`)} ${b.description}`);
1312
+ lines.push(chalk.dim(` ${b.details}`));
1313
+ }
1314
+ lines.push("");
1315
+ }
1316
+ if (result.aspects && result.aspects.length > 0) {
1317
+ lines.push(chalk.bold.cyan("\u2500\u2500 KEY ASPECTS \u2500\u2500"));
1318
+ for (const asp of result.aspects.slice(0, 10)) {
1319
+ const aspSymbol = getAspectSymbol(asp.aspect);
1320
+ lines.push(` ${asp.planet1} ${aspSymbol} ${asp.aspect} ${asp.planet2} ${chalk.dim(`(orb: ${asp.orb}\xB0)`)}`);
1321
+ }
1322
+ lines.push("");
1323
+ }
1324
+ return lines.join("\n");
1325
+ }
1326
+ function formatMoonExtended(result) {
1327
+ const lines = [];
1328
+ lines.push("");
1329
+ lines.push(chalk.bold.hex("#C0C0C0")(`\u{1F319} Moon Extended \u2014 ${result.datetime}`));
1330
+ lines.push(` Location: ${result.location.lat}\xB0, ${result.location.lng}\xB0 (${result.location.timezone})`);
1331
+ lines.push("");
1332
+ const moon2 = result.moon;
1333
+ const moonColor = COLORS.moon;
1334
+ lines.push(chalk.bold.cyan("\u2500\u2500 MOON \u2500\u2500"));
1335
+ lines.push(` ${moon2.emoji} ${chalk.bold(moon2.phase_name)} (${moon2.stage})`);
1336
+ lines.push(` ${moonColor(getZodiacSymbol(moon2.sign))} Moon in ${moon2.sign}`);
1337
+ lines.push(` Illumination: ${moon2.illumination}`);
1338
+ lines.push(` Age: ${moon2.age_days} days`);
1339
+ lines.push("");
1340
+ const sun = result.sun;
1341
+ lines.push(chalk.bold.cyan("\u2500\u2500 SUN \u2500\u2500"));
1342
+ lines.push(` \u2600\uFE0F Sunrise: ${sun.sunrise} | Sunset: ${sun.sunset}`);
1343
+ lines.push(` Solar noon: ${sun.solar_noon} | Day length: ${sun.day_length}`);
1344
+ lines.push("");
1345
+ lines.push(chalk.bold.cyan("\u2500\u2500 ECLIPSES \u2500\u2500"));
1346
+ if (moon2.next_lunar_eclipse) {
1347
+ lines.push(` \u{1F311} Next Lunar Eclipse: ${moon2.next_lunar_eclipse.date}`);
1348
+ lines.push(` Type: ${moon2.next_lunar_eclipse.type}`);
1349
+ }
1350
+ if (sun.next_solar_eclipse) {
1351
+ lines.push(` \u2600\uFE0F Next Solar Eclipse: ${sun.next_solar_eclipse.date}`);
1352
+ lines.push(` Type: ${sun.next_solar_eclipse.type}`);
1353
+ }
1354
+ lines.push("");
1355
+ if (result.upcoming_phases) {
1356
+ lines.push(chalk.bold.cyan("\u2500\u2500 UPCOMING PHASES \u2500\u2500"));
1357
+ const phases = ["new_moon", "first_quarter", "full_moon", "last_quarter"];
1358
+ const phaseEmojis = {
1359
+ "new_moon": "\u{1F311}",
1360
+ "first_quarter": "\u{1F313}",
1361
+ "full_moon": "\u{1F315}",
1362
+ "last_quarter": "\u{1F317}"
1363
+ };
1364
+ for (const phase of phases) {
1365
+ const data = result.upcoming_phases[phase];
1366
+ if (data && data.next) {
1367
+ const emoji = phaseEmojis[phase] || "\u{1F319}";
1368
+ const name = phase.replace("_", " ").replace(/\b\w/g, (c) => c.toUpperCase());
1369
+ lines.push(` ${emoji} ${name}: ${data.next} ${chalk.dim(`(${data.days_until_next} days)`)}`);
1370
+ }
1371
+ }
1372
+ lines.push("");
1373
+ }
1374
+ return lines.join("\n");
1375
+ }
1376
+ function formatTransitScan(result) {
1377
+ const lines = [];
1378
+ lines.push("");
1379
+ lines.push(chalk.bold.blue("\u{1F52D} Transit Scan"));
1380
+ lines.push(` Natal: ${result.natal.date}`);
1381
+ lines.push(` Range: ${result.scan_range.start} to ${result.scan_range.end}`);
1382
+ lines.push(` Step: ${result.scan_range.step} | Orb: ${result.scan_range.orb}\xB0`);
1383
+ lines.push(` Found: ${result.total_hits} transit hits`);
1384
+ lines.push("");
1385
+ if (result.hits && result.hits.length > 0) {
1386
+ lines.push(chalk.bold.cyan("\u2500\u2500 TRANSIT HITS \u2500\u2500"));
1387
+ let currentDate = "";
1388
+ for (const hit of result.hits) {
1389
+ if (hit.date !== currentDate) {
1390
+ currentDate = hit.date;
1391
+ lines.push("");
1392
+ lines.push(chalk.bold(` \u{1F4C5} ${hit.date}`));
1393
+ }
1394
+ const tColor = getPlanetColor(hit.transit_planet.toLowerCase());
1395
+ const nColor = getPlanetColor(hit.natal_planet.toLowerCase());
1396
+ const aspSymbol = getAspectSymbol(hit.aspect);
1397
+ lines.push(` ${tColor(hit.transit_planet)} ${aspSymbol} ${hit.aspect.slice(0, 4)} ${nColor(hit.natal_planet)} ${chalk.dim(`(${hit.orb.toFixed(2)}\xB0)`)}`);
1398
+ }
1399
+ lines.push("");
1400
+ }
1401
+ return lines.join("\n");
1402
+ }
1403
+ function formatEphemerisMulti(result) {
1404
+ const lines = [];
1405
+ lines.push("");
1406
+ lines.push(chalk.bold.cyan("\u{1F4CA} Multi-Body Ephemeris"));
1407
+ lines.push(` Bodies: ${result.bodies.join(", ")}`);
1408
+ lines.push(` Range: ${result.range.start} to ${result.range.end}`);
1409
+ lines.push(` Step: ${result.range.step} | Points: ${result.total_points}`);
1410
+ lines.push("");
1411
+ lines.push(chalk.bold.cyan("\u2500\u2500 POSITIONS \u2500\u2500"));
1412
+ const bodyHeaders = result.bodies.map((b) => b.slice(0, 6).padEnd(8)).join("");
1413
+ lines.push(` ${chalk.dim("Date".padEnd(12))}${bodyHeaders}`);
1414
+ lines.push(chalk.dim(" " + "\u2500".repeat(12 + result.bodies.length * 8)));
1415
+ for (const pos of result.positions.slice(0, 30)) {
1416
+ const date = pos.datetime.slice(0, 10);
1417
+ let row = ` ${date} `;
1418
+ for (const body of result.bodies) {
1419
+ const data = pos[body];
1420
+ if (data && typeof data === "object") {
1421
+ const sign = data.sign.slice(0, 3);
1422
+ const deg = Math.floor(data.position);
1423
+ const color = getZodiacColor(sign);
1424
+ row += color(`${sign}${deg}\xB0`.padEnd(8));
1425
+ } else {
1426
+ row += "".padEnd(8);
1427
+ }
1428
+ }
1429
+ lines.push(row);
1430
+ }
1431
+ if (result.positions.length > 30) {
1432
+ lines.push(chalk.dim(` ... and ${result.positions.length - 30} more rows (use --json for full data)`));
1433
+ }
1434
+ lines.push("");
1435
+ return lines.join("\n");
1436
+ }
1174
1437
 
1175
1438
  // src/types.ts
1176
1439
  function isError(result) {
@@ -1191,6 +1454,10 @@ export {
1191
1454
  solarArc,
1192
1455
  horary,
1193
1456
  version,
1457
+ score,
1458
+ moonExtended,
1459
+ transitScan,
1460
+ ephemerisMulti,
1194
1461
  getZodiacSymbol,
1195
1462
  getPlanetSymbol,
1196
1463
  getAspectSymbol,
@@ -1207,5 +1474,9 @@ export {
1207
1474
  formatComposite,
1208
1475
  formatSolarArc,
1209
1476
  formatHorary,
1477
+ formatScore,
1478
+ formatMoonExtended,
1479
+ formatTransitScan,
1480
+ formatEphemerisMulti,
1210
1481
  isError
1211
1482
  };
package/dist/index.d.ts CHANGED
@@ -498,6 +498,179 @@ interface ThothError {
498
498
  }
499
499
  type ThothResult<T> = T | ThothError;
500
500
  declare function isError<T extends object>(result: ThothResult<T>): result is ThothError;
501
+ interface ScoreOptions {
502
+ year1: number;
503
+ month1: number;
504
+ day1: number;
505
+ hour1?: number;
506
+ minute1?: number;
507
+ city1?: string;
508
+ nation1?: string;
509
+ lat1?: number;
510
+ lng1?: number;
511
+ name1?: string;
512
+ year2: number;
513
+ month2: number;
514
+ day2: number;
515
+ hour2?: number;
516
+ minute2?: number;
517
+ city2?: string;
518
+ nation2?: string;
519
+ lat2?: number;
520
+ lng2?: number;
521
+ name2?: string;
522
+ }
523
+ interface ScoreResult {
524
+ type: string;
525
+ person1: {
526
+ name: string;
527
+ date: string;
528
+ sun: string;
529
+ moon: string;
530
+ ascendant?: string;
531
+ };
532
+ person2: {
533
+ name: string;
534
+ date: string;
535
+ sun: string;
536
+ moon: string;
537
+ ascendant?: string;
538
+ };
539
+ score: {
540
+ value: number;
541
+ description: string;
542
+ is_destiny_sign: boolean;
543
+ };
544
+ breakdown: Array<{
545
+ rule: string;
546
+ description: string;
547
+ points: number;
548
+ details: string;
549
+ }>;
550
+ aspects: Array<{
551
+ planet1: string;
552
+ planet2: string;
553
+ aspect: string;
554
+ orb: number;
555
+ }>;
556
+ }
557
+ interface MoonExtendedOptions {
558
+ year?: number;
559
+ month?: number;
560
+ day?: number;
561
+ lat?: number;
562
+ lng?: number;
563
+ tz?: string;
564
+ }
565
+ interface MoonExtendedResult {
566
+ type: string;
567
+ datetime: string;
568
+ location: {
569
+ lat: number;
570
+ lng: number;
571
+ timezone: string;
572
+ };
573
+ sun: {
574
+ sunrise: string;
575
+ sunset: string;
576
+ solar_noon: string;
577
+ day_length: string;
578
+ next_solar_eclipse?: {
579
+ date: string;
580
+ type: string;
581
+ };
582
+ };
583
+ moon: {
584
+ sign: string;
585
+ phase_name: string;
586
+ major_phase: string;
587
+ stage: string;
588
+ illumination: string;
589
+ age_days: number;
590
+ emoji: string;
591
+ moonrise?: string;
592
+ moonset?: string;
593
+ next_lunar_eclipse?: {
594
+ date: string;
595
+ type: string;
596
+ };
597
+ };
598
+ upcoming_phases?: Record<string, {
599
+ last?: string;
600
+ next?: string;
601
+ days_until_next?: number;
602
+ }>;
603
+ }
604
+ interface TransitScanOptions {
605
+ natalYear: number;
606
+ natalMonth: number;
607
+ natalDay: number;
608
+ natalHour?: number;
609
+ natalMinute?: number;
610
+ natalCity?: string;
611
+ nation?: string;
612
+ natalLat?: number;
613
+ natalLng?: number;
614
+ startYear: number;
615
+ startMonth?: number;
616
+ startDay?: number;
617
+ endYear: number;
618
+ endMonth?: number;
619
+ endDay?: number;
620
+ orb?: number;
621
+ step?: 'day' | 'week';
622
+ }
623
+ interface TransitScanResult {
624
+ type: string;
625
+ natal: {
626
+ date: string;
627
+ };
628
+ scan_range: {
629
+ start: string;
630
+ end: string;
631
+ step: string;
632
+ orb: number;
633
+ };
634
+ hits: Array<{
635
+ date: string;
636
+ transit_planet: string;
637
+ aspect: string;
638
+ natal_planet: string;
639
+ orb: number;
640
+ }>;
641
+ total_hits: number;
642
+ }
643
+ interface EphemerisMultiOptions {
644
+ bodies?: string;
645
+ startYear: number;
646
+ startMonth?: number;
647
+ startDay?: number;
648
+ endYear: number;
649
+ endMonth?: number;
650
+ endDay?: number;
651
+ step?: 'hour' | 'day' | 'week' | 'month';
652
+ lat?: number;
653
+ lng?: number;
654
+ }
655
+ interface EphemerisMultiResult {
656
+ type: string;
657
+ bodies: string[];
658
+ range: {
659
+ start: string;
660
+ end: string;
661
+ step: string;
662
+ };
663
+ positions: Array<{
664
+ datetime: string;
665
+ [body: string]: {
666
+ sign: string;
667
+ position: number;
668
+ abs_position: number;
669
+ retrograde: boolean;
670
+ } | string;
671
+ }>;
672
+ total_points: number;
673
+ }
501
674
 
502
675
  /**
503
676
  * Core wrapper for thoth-core binary
@@ -558,6 +731,22 @@ declare function horary(options: HoraryOptions): Promise<ThothResult<HoraryResul
558
731
  declare function version(): Promise<ThothResult<{
559
732
  version: string;
560
733
  }>>;
734
+ /**
735
+ * Calculate relationship compatibility score
736
+ */
737
+ declare function score(options: ScoreOptions): Promise<ThothResult<ScoreResult>>;
738
+ /**
739
+ * Get extended moon data with eclipses
740
+ */
741
+ declare function moonExtended(options: MoonExtendedOptions): Promise<ThothResult<MoonExtendedResult>>;
742
+ /**
743
+ * Scan for transits over a date range
744
+ */
745
+ declare function transitScan(options: TransitScanOptions): Promise<ThothResult<TransitScanResult>>;
746
+ /**
747
+ * Get multi-body ephemeris over a date range
748
+ */
749
+ declare function ephemerisMulti(options: EphemerisMultiOptions): Promise<ThothResult<EphemerisMultiResult>>;
561
750
 
562
751
  /**
563
752
  * Output formatting utilities
@@ -628,5 +817,21 @@ declare function formatSolarArc(result: SolarArcResult): string;
628
817
  * Format horary chart result
629
818
  */
630
819
  declare function formatHorary(result: HoraryResult): string;
820
+ /**
821
+ * Format relationship compatibility score
822
+ */
823
+ declare function formatScore(result: any): string;
824
+ /**
825
+ * Format extended moon data
826
+ */
827
+ declare function formatMoonExtended(result: any): string;
828
+ /**
829
+ * Format transit scan results
830
+ */
831
+ declare function formatTransitScan(result: any): string;
832
+ /**
833
+ * Format multi-body ephemeris
834
+ */
835
+ declare function formatEphemerisMulti(result: any): string;
631
836
 
632
- export { type Aspect, type ChartOptions, type ChartResult, type CompositeOptions, type CompositeResult, type DirectedPlanet, type EphemerisOptions, type EphemerisPosition, type EphemerisRangeOptions, type EphemerisRangeResult, type EphemerisResult, type HoraryHouse, type HoraryOptions, type HoraryResult, type House, type LunarPhase, type LunarReturnOptions, type LunarReturnResult, type MoonAspect, type MoonOptions, type MoonResult, type Planet, type ProgressionsOptions, type ProgressionsResult, type RetrogradeStation, type SignChange, type SolarArcOptions, type SolarArcResult, type SolarReturnOptions, type SolarReturnResult, type SynastryOptions, type SynastryResult, type ThothError, type ThothResult, type TransitOptions, type TransitResult, chart, composite, ephemeris, ephemerisRange, formatChart, formatComposite, formatDegrees, formatEphemeris, formatEphemerisRange, formatHorary, formatLunarReturn, formatMoon, formatProgressions, formatSolarArc, formatSolarReturn, formatSynastry, formatTransits, getAspectSymbol, getPlanetSymbol, getZodiacSymbol, horary, isError, lunarReturn, moon, progressions, solarArc, solarReturn, synastry, transit, version };
837
+ export { type Aspect, type ChartOptions, type ChartResult, type CompositeOptions, type CompositeResult, type DirectedPlanet, type EphemerisMultiOptions, type EphemerisMultiResult, type EphemerisOptions, type EphemerisPosition, type EphemerisRangeOptions, type EphemerisRangeResult, type EphemerisResult, type HoraryHouse, type HoraryOptions, type HoraryResult, type House, type LunarPhase, type LunarReturnOptions, type LunarReturnResult, type MoonAspect, type MoonExtendedOptions, type MoonExtendedResult, type MoonOptions, type MoonResult, type Planet, type ProgressionsOptions, type ProgressionsResult, type RetrogradeStation, type ScoreOptions, type ScoreResult, type SignChange, type SolarArcOptions, type SolarArcResult, type SolarReturnOptions, type SolarReturnResult, type SynastryOptions, type SynastryResult, type ThothError, type ThothResult, type TransitOptions, type TransitResult, type TransitScanOptions, type TransitScanResult, chart, composite, ephemeris, ephemerisMulti, ephemerisRange, formatChart, formatComposite, formatDegrees, formatEphemeris, formatEphemerisMulti, formatEphemerisRange, formatHorary, formatLunarReturn, formatMoon, formatMoonExtended, formatProgressions, formatScore, formatSolarArc, formatSolarReturn, formatSynastry, formatTransitScan, formatTransits, getAspectSymbol, getPlanetSymbol, getZodiacSymbol, horary, isError, lunarReturn, moon, moonExtended, progressions, score, solarArc, solarReturn, synastry, transit, transitScan, version };
package/dist/index.js CHANGED
@@ -2,19 +2,24 @@ import {
2
2
  chart,
3
3
  composite,
4
4
  ephemeris,
5
+ ephemerisMulti,
5
6
  ephemerisRange,
6
7
  formatChart,
7
8
  formatComposite,
8
9
  formatDegrees,
9
10
  formatEphemeris,
11
+ formatEphemerisMulti,
10
12
  formatEphemerisRange,
11
13
  formatHorary,
12
14
  formatLunarReturn,
13
15
  formatMoon,
16
+ formatMoonExtended,
14
17
  formatProgressions,
18
+ formatScore,
15
19
  formatSolarArc,
16
20
  formatSolarReturn,
17
21
  formatSynastry,
22
+ formatTransitScan,
18
23
  formatTransits,
19
24
  getAspectSymbol,
20
25
  getPlanetSymbol,
@@ -23,30 +28,38 @@ import {
23
28
  isError,
24
29
  lunarReturn,
25
30
  moon,
31
+ moonExtended,
26
32
  progressions,
33
+ score,
27
34
  solarArc,
28
35
  solarReturn,
29
36
  synastry,
30
37
  transit,
38
+ transitScan,
31
39
  version
32
- } from "./chunk-SURUD7BV.js";
40
+ } from "./chunk-QND56LGZ.js";
33
41
  export {
34
42
  chart,
35
43
  composite,
36
44
  ephemeris,
45
+ ephemerisMulti,
37
46
  ephemerisRange,
38
47
  formatChart,
39
48
  formatComposite,
40
49
  formatDegrees,
41
50
  formatEphemeris,
51
+ formatEphemerisMulti,
42
52
  formatEphemerisRange,
43
53
  formatHorary,
44
54
  formatLunarReturn,
45
55
  formatMoon,
56
+ formatMoonExtended,
46
57
  formatProgressions,
58
+ formatScore,
47
59
  formatSolarArc,
48
60
  formatSolarReturn,
49
61
  formatSynastry,
62
+ formatTransitScan,
50
63
  formatTransits,
51
64
  getAspectSymbol,
52
65
  getPlanetSymbol,
@@ -55,10 +68,13 @@ export {
55
68
  isError,
56
69
  lunarReturn,
57
70
  moon,
71
+ moonExtended,
58
72
  progressions,
73
+ score,
59
74
  solarArc,
60
75
  solarReturn,
61
76
  synastry,
62
77
  transit,
78
+ transitScan,
63
79
  version
64
80
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thoth-cli",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "description": "𓅝 Astrological calculations from the command line. Swiss Ephemeris precision. Built for humans and agents.",
5
5
  "author": "AKLO <aklo@aklolabs.com>",
6
6
  "license": "MIT",
@@ -14,7 +14,7 @@ import https from 'https';
14
14
 
15
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
16
 
17
- const VERSION = '0.2.15';
17
+ const VERSION = '0.2.17';
18
18
  const REPO = 'aklo360/thoth-cli';
19
19
 
20
20
  // Use jsDelivr CDN for faster downloads (mirrors GitHub releases)