# bazi-core

一个可解释、可追溯的 TypeScript 八字计算与规则分析引擎。

`bazi-core` 负责把中国标准时间的公历输入转换为四柱，并提供季节环境、藏干十神、根气、干支关系、旺衰、大运、流年等结构化结果。重要结果会公开实际采用的规则、推导过程和能力边界。

它不会用伪精确的五行百分比包装结论，也不会把合、冲、刑、害直接解释成吉凶或具体人生事件。

## 设计原则

- **计算与解释分离**：历法、四柱和时间线属于计算层；十神、根气和干支关系属于事实层；旺衰或未来的流派判断属于解释层。
- **规则显式可追溯**：重要结果保留 `model`、`appliedRules`、`trace` 和 `warnings`。
- **旧模型保持稳定**：新增规则通过新的模型版本演进，不静默修改已有 `*-v1`、`*-v2` 的含义。

## 安装

```bash
npm install bazi-core
```

包内同时包含 ESM、CommonJS、TypeScript 类型声明和完整 `src/` 源码，具体规则可以直接审查。

## 应该使用哪个 API

| 需求 | API | 主要结果 |
| --- | --- | --- |
| 出生时间排完整八字 | `calculateBazi` | 四柱、藏干、十神、季节、关系、根气、旺衰 |
| 计算起运和十年大运 | `calculateLuckCycles` | 顺逆、起运年龄、交运时间、大运时间线 |
| 分析大运与原局关系 | `analyzeLuckCycles` | 每步大运的十神、根气、十二长生、合克刑冲害事实 |
| 生成流年时间线 | `calculateAnnualCycles` | 按立春分段的流年干支及精确起止时间 |
| 已知四柱，直接分析 | `calculateFromPillars` | 标准化命盘、关系、根气、旺衰 v1/v2 |
| 已知四柱，只算旺衰 | `analyzePillars` / `analyzePillarsV2` | 指定版本的旺衰分析结果 |

`detectPillarRelations`、`detectPillarRoots`、`getTenGod`、`getTwelveGrowthStage` 等底层函数也可以独立使用。

## 快速开始：完整排盘

```ts
import { calculateBazi } from 'bazi-core';

const birthInput = {
  civilTime: {
    year: 1995,
    month: 1,
    day: 21,
    hour: 11,
    minute: 30,
  },
};

const result = calculateBazi(birthInput);

console.log(
  Object.values(result.pillars).map((pillar) => pillar.ganZhi),
);
// ['甲戌', '丁丑', '壬子', '丙午']

console.log(result.dayMaster);               // 日主
console.log(result.pillars);                 // 完整四柱、五行、十神和藏干
console.log(result.seasonContext);           // 节气、十二长生、旺相休囚死
console.log(result.relations);               // 原局天干合克、地支刑冲合害
console.log(result.roots);                   // 根气位置和本中余气层级
console.log(result.analysis);                // ziping-strength-v1
console.log(result.analysisV2);              // ziping-strength-v2
console.log(result.appliedRules);            // 本次采用的规则
console.log(result.trace);                   // 从时间到结果的推导链
console.log(result.warnings);                // 当前模型边界
```

输入是中国标准时间 `UTC+08:00` 的公历民用时间组件，不接收容易产生时区歧义的 JavaScript `Date`。

### 选择换日规则

```ts
const result = calculateBazi(
  {
    civilTime: {
      year: 2024,
      month: 2,
      day: 10,
      hour: 23,
      minute: 30,
    },
  },
  {
    // 默认 midnight，即 00:00 换日；zi-hour 表示 23:00 换日
    dayBoundary: 'zi-hour',
  },
);
```

## 起运与十年大运

```ts
import { calculateLuckCycles } from 'bazi-core';

const luckCycles = calculateLuckCycles(birthInput, {
  // 只用于所选传统顺逆规则，不改变出生四柱
  sexForRule: 'male',
  cycleCount: 8,
});

console.log(luckCycles.sourcePillars);       // 原局四柱的简洁干支形式
console.log(luckCycles.direction);           // forward
console.log(luckCycles.directionReason);     // 为什么顺排
console.log(luckCycles.boundaryTerm);        // 起运采用的节令和距离
console.log(luckCycles.startAge);            // 起运年龄
console.log(luckCycles.startsAt);            // 精确交运时间
console.log(luckCycles.cycles[0]);           // 第一步十年大运
```

不使用年干阴阳与性别定顺逆的传统规则时，可以直接指定方向：

```ts
const luckCycles = calculateLuckCycles(birthInput, {
  direction: 'reverse',
});
```

`luck-cycle-v1` 只计算时间和干支，不判断某一步是不是好运。完整规则见 [docs/luck-cycle.md](./docs/luck-cycle.md)。

## 大运与原局关系事实

```ts
import { analyzeLuckCycles } from 'bazi-core';

const luckAnalysis = analyzeLuckCycles(birthInput, {
  sexForRule: 'male',
  cycleCount: 8,
});

console.log(luckAnalysis.sourcePillars);
// { year: '甲戌', month: '丁丑', day: '壬子', hour: '丙午' }

console.log(luckAnalysis.dayMaster);
// { stem: '壬', element: 'water', yinYang: 'yang' }

const first = luckAnalysis.cycles[0];
console.log(first.cycle);                    // 戊寅大运的年龄与时间区间
console.log(first.stem.tenGod);              // 七杀
console.log(first.branch.hiddenStems);       // 寅支藏干及其十神
console.log(first.branch.twelveGrowth);      // 壬在寅的十二长生
console.log(first.branch.root);              // 寅支是否给壬水增加同五行根气
console.log(first.relations.stems);          // 大运干与原局四干的合克
console.log(first.relations.branches);       // 大运支参与的合冲刑害
```

`luck-analysis-v1` 只输出当前大运参与的结构化关系：

- 天干五合与有方向的相克；
- 地支六合、完整三合、六冲、六害、子卯刑、自刑和完整三刑；
- 合化只标记 `candidate-only`，不表示已经化成目标五行；
- 不删除原局干支，不修改原局旺衰，不生成吉凶或事件断语。

完整规则见 [docs/luck-analysis.md](./docs/luck-analysis.md)。

### `pillars` 与 `sourcePillars` 的区别

`calculateBazi().pillars` 是完整结构，每一柱都包含天干、地支、五行、阴阳、十神和藏干。

`calculateLuckCycles().sourcePillars` 和 `analyzeLuckCycles().sourcePillars` 是大运计算所依据的原局四柱，使用简洁的干支字符串：

```json
{
  "year": "甲戌",
  "month": "丁丑",
  "day": "壬子",
  "hour": "丙午"
}
```

如果一个业务页面同时需要完整命盘和大运关系，可以分别调用：

```ts
const chart = calculateBazi(birthInput);
const luck = analyzeLuckCycles(birthInput, {
  sexForRule: 'male',
  cycleCount: 8,
});
```

两个 API 使用相同的四柱历法核心，大运结果中的 `sourcePillars` 可用于核对原局来源。

## 流年时间线

```ts
import { calculateAnnualCycles } from 'bazi-core';

const annualCycles = calculateAnnualCycles({
  fromYear: 2024,
  toYear: 2026,
});

console.log(annualCycles.cycles.map((cycle) => cycle.ganZhi));
// ['甲辰', '乙巳', '丙午']

console.log(annualCycles.cycles[0]);
// {
//   index: 1,
//   anchorYear: 2024,
//   ganZhi: '甲辰',
//   startsAt: '2024-02-04T16:27:07+08:00',
//   endsAt: '2025-02-03T22:10:28+08:00'
// }
```

每个流年采用 `[本年立春, 次年立春)` 区间，不以公历元旦或农历正月初一换年。`annual-cycle-v1` 不判断流年吉凶，完整规则见 [docs/annual-cycle.md](./docs/annual-cycle.md)。

## 已知四柱时直接分析

```ts
import {
  analyzePillars,
  analyzePillarsV2,
  calculateFromPillars,
} from 'bazi-core';

const pillars = {
  year: '庚午',
  month: '辛巳',
  day: '壬午',
  hour: '丁未',
};

const analysisV1 = analyzePillars(pillars);
const analysisV2 = analyzePillarsV2(pillars);

const result = calculateFromPillars(pillars);
console.log(result.chart);
console.log(result.relations);
console.log(result.roots);
console.log(result.analysis);
console.log(result.analysisV2);
```

纯四柱输入没有出生时刻，因此不能还原节气的精确秒级距离，但仍可根据月支计算季节状态和核心十二长生事实。

## 当前模型

| 模型 | 作用 | 详细规则 |
| --- | --- | --- |
| `relations-v1` | 原局天干合克、地支刑冲合害事实 | [docs/relations.md](./docs/relations.md) |
| `season-context-v1` | 节气距离、十二长生、旺相休囚死 | [docs/season-context.md](./docs/season-context.md) |
| `roots-v1` | 日主同五行藏干及根气位置 | [docs/roots.md](./docs/roots.md) |
| `ziping-strength-v1` | 保留的首版旺衰模型 | [docs/algorithm.md](./docs/algorithm.md) |
| `ziping-strength-v2` | 显式组合季节、根气和关系事实 | [docs/algorithm-v2.md](./docs/algorithm-v2.md) |
| `luck-cycle-v1` | 起运与十年大运时间线 | [docs/luck-cycle.md](./docs/luck-cycle.md) |
| `luck-analysis-v1` | 大运与原局关系事实 | [docs/luck-analysis.md](./docs/luck-analysis.md) |
| `annual-cycle-v1` | 按立春分段的流年时间线 | [docs/annual-cycle.md](./docs/annual-cycle.md) |

## 可追溯结果的常见字段

- `model`：本次结果采用的版本化模型；
- `appliedRules`：实际启用的历法或分析口径；
- `trace`：机器可读的输入、规则与输出推导链；
- `warnings`：未建模、存在流派差异或不应过度解释的边界；
- `candidateElement`：传统合局中的候选化行，不表示合化成功；
- 时间区间统一使用前闭后开 `[startsAt, endsAt)`。

## 当前边界

- 只接受中国标准时间的公历民用时间；
- 不计算经度修正、真太阳时和夏令时；
- 年柱以立春换年，月柱以十二“节”换月；
- 不自动判断从格、专旺、化气、假从、调候和用神；
- 不把合、冲、刑、害自动换算成吉凶；
- 不生成性格、婚恋、财运、健康或具体事件断语；
- 旺衰只是公开规则模型的结果，不是科学预测，也不应代替现实决策。

历法边界回归向量覆盖立春换年、节换月、两种子时换日、闰日和年末场景，维护规则见 [docs/testing.md](./docs/testing.md)。

## 开发

```bash
npm install
npm run check
```

`npm run check` 会依次执行严格类型检查、完整 Vitest 测试，并构建 ESM、CommonJS 和 `.d.ts` 类型声明。

## 发布前检查

1. 检查 `package.json` 中的版本、作者、许可和发布配置；
2. 执行 `npm whoami` 确认当前 npm 账号；
3. 执行 `npm run check`；
4. 执行 `npm pack --dry-run`，检查压缩包内容；
5. 在临时项目中分别验证 ESM、CommonJS 和类型声明；
6. 确认目标版本未发布后，执行 `npm publish --access public`。

## 许可

本项目使用 [MIT License](./LICENSE)。历法部分依赖同为 MIT 许可的 [`lunar-typescript`](https://github.com/6tail/lunar-typescript)，详见 [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md)。

版本变更见 [CHANGELOG.md](./CHANGELOG.md)。
