dsh-metaphysics 0.19.0 → 0.20.0

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/CHANGELOG.md CHANGED
@@ -2,16 +2,28 @@
2
2
 
3
3
  版本按「一组可感知的改动」发,README 与市场条目描述随能力同步。
4
4
 
5
- ## 0.19.0(已发布)
6
-
7
- 黄历、择日、公农历互转三处按「吉历」的用法补齐(只吸收合适的那部分,不搬它的小工具):
8
-
9
- - **黄历增强**:值日十二神(黄道/黑道)、十二时辰吉凶(五鼠遁定干支 + 时家十二神,逐时标吉凶)、二十八宿(吉凶/七政/禽/宫)、胎神、财神/喜神/福神/阳贵/阴贵方位、日柱纳音、六合三合吉配生肖;值日神/二十八宿/胎神/吉神方位与 lunar-javascript 逐日对拍(60 天仅交节当日 1 处日界差异,已注明口径)。
10
- - **择日扩充**:事项从 13 类扩到 27 类(领证/提亲/收送聘金/满月酒/交易/投资/签订合同/搬家入宅/装修建造/试车买车/旅行/赴任/访亲友/入学…),面板与独立页按「常用 / 婚嫁 / 生活 / 建造 / 工商」五组下拉归类;打分与冲属相排除口径不变。
11
- - **公农历互转 `convert`**:新增体系。公历 → 农历(农历年月日、闰月、干支四柱、生肖)与农历 → 公历(闰月须显式指定,小月无三十报错),往返自洽;只知道农历生日时可先转公历再排盘。工具层与面板、独立页都已接入。
12
- - 面板与独立页 tab 由 17 个扩到 **18 个**;黄历 tab 有专属卡片(值日徽标、宜忌、四格、吉神方位、十二时辰吉凶网格)。
13
- - 测试新增 `test/tools3.test.mjs`(14 条:黄历新增字段定值、五鼠遁、十二时辰吉凶、公农历往返/闰月/报错、择日分组与冲属相排除、渲染与接线)。
14
-
5
+ ## 0.20.0(已发布)
6
+
7
+ 调候(寒暖燥湿)不再是脚注:从「扶抑为主 + 一句提示」改成「调候优先 + 扶抑校验」的判定层。
8
+
9
+ - 新增 `engine/tiaohou.js`:按月令基础温度、全局火水比例、湿土燥土给出 **寒 / 寒湿 / 寒燥 / 湿滞 / 平 / 燥 / 燥热 / 温热** 八档气候,附温度与燥湿量化值和依据(如「季冬丑月、火0、水1.8、湿土2处」);由此定调候所取(寒湿取丙火、燥热取壬水)与所忌。偏寒偏燥明显时判「调候优先」,否则「扶抑为主」。
10
+ - **用神仲裁**:调候所需与扶抑喜忌冲突时显式裁决并说明理由(「寒暖失衡时再补强弱也难受」),不冲突时写「两套取法同向,不必取舍」;`method` 字段改成「调候优先 + 扶抑校验」/「扶抑为主 + 调候校验」,读得出来用了哪套。
11
+ - **评分接入调候**:流年/大运评分里,调候优先时天干地支合调候所需加权,合所忌扣权,寒局再逢水再扣(「地支子水加重寒湿」)。以 1996-01-19 盘为例:2020 庚子由「平 0.5」改为「忌 −0.8」并写明水助寒湿;2026 丙午「大吉 4.0」写明「寒湿之局得丙火,解冻」。
12
+ - **解释层**新增「寒暖燥湿」一节:气候判定 + 体感白话(按日主五行各写一句)+ 调候取忌 + 仲裁;八字文本摘要加「寒暖:」一行。
13
+ - **面板**在「用神」下新增寒暖卡:气候标签、调候优先徽标、寒—平—热标尺、调候取/忌/依据、白话叙述;独立页与面板共用。
14
+ - 口径:调候由月令与全局寒暖燥湿判定,未逐条录入《穷通宝鉴》120 条;调候与扶抑的优先级各家有争论,界面与文档都写明采用的是「调候优先、扶抑校验」。
15
+ - 测试新增 `test/tiaohou.test.mjs`(32 条:寒/热两盘、仲裁同向与冲突、评分方向与上下限、解释节、摘要行、面板卡);统计 61 个测试文件 / 1714 条断言。
16
+
17
+ ## 0.19.0(已发布)
18
+
19
+ 黄历、择日、公农历互转三处按「吉历」的用法补齐(只吸收合适的那部分,不搬它的小工具):
20
+
21
+ - **黄历增强**:值日十二神(黄道/黑道)、十二时辰吉凶(五鼠遁定干支 + 时家十二神,逐时标吉凶)、二十八宿(吉凶/七政/禽/宫)、胎神、财神/喜神/福神/阳贵/阴贵方位、日柱纳音、六合三合吉配生肖;值日神/二十八宿/胎神/吉神方位与 lunar-javascript 逐日对拍(60 天仅交节当日 1 处日界差异,已注明口径)。
22
+ - **择日扩充**:事项从 13 类扩到 27 类(领证/提亲/收送聘金/满月酒/交易/投资/签订合同/搬家入宅/装修建造/试车买车/旅行/赴任/访亲友/入学…),面板与独立页按「常用 / 婚嫁 / 生活 / 建造 / 工商」五组下拉归类;打分与冲属相排除口径不变。
23
+ - **公农历互转 `convert`**:新增体系。公历 → 农历(农历年月日、闰月、干支四柱、生肖)与农历 → 公历(闰月须显式指定,小月无三十报错),往返自洽;只知道农历生日时可先转公历再排盘。工具层与面板、独立页都已接入。
24
+ - 面板与独立页 tab 由 17 个扩到 **18 个**;黄历 tab 有专属卡片(值日徽标、宜忌、四格、吉神方位、十二时辰吉凶网格)。
25
+ - 测试新增 `test/tools3.test.mjs`(14 条:黄历新增字段定值、五鼠遁、十二时辰吉凶、公农历往返/闰月/报错、择日分组与冲属相排除、渲染与接线)。
26
+
15
27
  ## 0.18.4(已发布)
16
28
 
17
29
  称骨补上**称骨歌原文**与白话释义(此前只有自撰的分档批语):
package/README.md CHANGED
@@ -23,7 +23,7 @@ Chinese metaphysics (玄学 / xuanxue) for [DeepSeek Harness](https://github.com
23
23
  风水(八宅命卦/大游年/流年紫白/门主灶)、起名(喜用五行匹配,未收录如实标注)——口径与边界各自写明
24
24
  - 全部本地计算,不收集数据;结果供文化娱乐参考,不作医疗、投资、法律或生死判断
25
25
 
26
- ### 报告化与可核验(0.16 / 0.17 / 0.18 新增)
26
+ ### 报告化与可核验(0.16 / 0.17 / 0.18 / 0.20 新增)
27
27
 
28
28
  - **一页读懂 + 三张表**:整体/事业/财富/感情/节奏五条摘要;大运表、流年表、触发事件表(紫微是大限/流年/触发)
29
29
  - **证据卡 + 置信度**:每条维度结论可展开到逐条盘面事实与所用技法,置信度按证据条数分强/中/弱
@@ -33,6 +33,7 @@ Chinese metaphysics (玄学 / xuanxue) for [DeepSeek Harness](https://github.com
33
33
  - **验前事**:列出过去几年流年信号,自评准/不准/不确定后算贴合度;只读,不改盘
34
34
  - **生时校正**:给定过去 2–3 件大事,对候选时辰逐一排盘打分排序;只缩小范围,不替代出生记录
35
35
  - **导出**:`.md`(盘面 + 解析)与 PNG 摘要长图(Canvas 直出,零依赖);独立页支持打印/存 PDF
36
+ - **调候解释**:解释层新增「寒暖燥湿」一节,文本摘要加「寒暖:」一行
36
37
  - **方法与验证页**:独立页内置静态页,写明对拍数据、测试与闸门、口径与已知边界
37
38
 
38
39
  ## 功能
@@ -42,7 +43,8 @@ Chinese metaphysics (玄学 / xuanxue) for [DeepSeek Harness](https://github.com
42
43
  - **十二长生**:地势(日干对各支)、自坐(各柱干对本支)
43
44
  - **神煞(42 星,7 类)**:贵人(天乙、太极、天德、月德、月德合、福星、天官、国印、天厨、天医)、文星(文昌、德秀)、婚姻(桃花、红鸾、天喜、孤辰、寡宿、金舆)、性情(华盖、羊刃、飞刃、魁罡、童子煞、六秀日、日德、日贵)、事业(禄神、将星、驿马)、凶煞(劫煞、灾煞、亡神、空亡、十恶大败、阴差阳错、四废日、流霞、天罗、地网)、格局(天赦日、金神、三奇贵人)。天干类双查年干与日干,三合类双查年支与日支;每颗星附查法依据,界面悬停可见
44
45
  - **日主旺衰**:月令权重 + 通根 + 天干帮扶,量化分档,并给出依据(季节权重、通根地支、帮扶/耗泄明细)
45
- - **格局与用神**:月令取格(建禄/阳刃/月劫/十神格)+特格(化气、专旺、从格)+十神组合(官印、杀印、食伤生财、财官、伤官配印、伤官见官、羊刃驾杀),每条附判定依据;用神取扶抑为主 + 简化调候提示,并列出喜忌十神
46
+ - **寒暖燥湿(调候优先)**:月令温度 + 全局火水比例 + 湿土燥土判定气候,给出调候所取(寒湿取丙火、燥热取壬水)与所忌、温度/燥湿标尺、按日主五行的体感白话;流年大运评分接入调候(寒局再逢水加重扣权);面板在「用神」下有寒暖卡
47
+ - **格局与用神**:月令取格(建禄/阳刃/月劫/十神格)+特格(化气、专旺、从格)+十神组合(官印、杀印、食伤生财、财官、伤官配印、伤官见官、羊刃驾杀),每条附判定依据;用神按「调候优先 + 扶抑校验」:先判寒暖燥湿(寒/寒湿/寒燥/湿滞/平/燥/燥热/温热,附温度与燥湿量化值与依据),调候所需与扶抑冲突时显式仲裁并说明理由,不冲突时注明同向;再列喜忌十神
46
48
  - **行运吉凶**:大运、流年按喜忌五行与十神加权评分,分大吉/吉/平/忌/大忌五档,悬停可看逐项理由
47
49
  - **干支关系**:五合、相冲、相克;六合、三合半合、三会半会拱会、冲、害、破、刑
48
50
  - 大运、流年(含与原局地支的关系)、真太阳时(按出生地经度修正)
@@ -108,7 +110,7 @@ Chinese metaphysics (玄学 / xuanxue) for [DeepSeek Harness](https://github.com
108
110
  - **追问**:工具参数 `ask`、面板与独立页的追问输入框——围绕**已算好的盘**回答「2027 年事业怎么样」「财运如何」这类问题;只取盘面已有字段(流年/大运/宫位/分节),不重排、不猜测;年份超出已排范围或没识别到方面时,明确说找不到并给出可问范围
109
111
  - **八字 × 紫微 交叉验证**:工具参数 `cross`(或面板勾选)会用同一份出生信息再排另一套盘,对事业/财富/感情/身体/节奏五项并列对照,标注「同向 / 有张力 / 互补」;只作对照,不把两套体系折算成同一个分数
110
112
  - **量化口径**:只量化引擎已有数据(十神权重、大运/流年档位、宫位与四化计数),**不换算金额、不给健康诊断**;报告里有「量化口径」分节写明这条边界
111
- - **方法与验证**:独立页内置同页「方法与验证」(体系、128 条卦例对拍、60 个测试文件/1682 条断言、七道闸、口径与已知边界),离线可开
113
+ - **方法与验证**:独立页内置同页「方法与验证」(体系、128 条卦例对拍、61 个测试文件/1714 条断言、七道闸、口径与已知边界),离线可开
112
114
  - **夏令时校正(0.18 新增)**:1986–1991 年中国夏令时期间的钟面时间在排盘前自动减 1 小时(跨日回退),八字/紫微/合盘/验前事/生时校正统一生效;出生证已是真实太阳口径时可用 `dst: false` 关闭
113
115
  - **合婚明细层(0.18 新增)**:合盘新增属相六合/三合/六冲/相害/相刑、天干五合、双向十神、跨盘地支、年命纳音与吉凶象计数分档;只作明细,不改原总分
114
116
  - **晚子时开关**:面板与独立页都能切「23:00 后算次日/当日」;奇门另可切「归当日/归次日」——这是排盘口径,不是结果重算
package/client.js CHANGED
@@ -746,7 +746,7 @@ function resolveAddress(input) {
746
746
 
747
747
  const DETAIL = /(区|县|镇|乡|村|小区|街道|路|号|巷|弄|组|队)/;
748
748
 
749
- const USER_AGENT = 'dsh-metaphysics/0.19.0 (+https://github.com/xuanfu-web/dsh-metaphysics)';
749
+ const USER_AGENT = 'dsh-metaphysics/0.20.0 (+https://github.com/xuanfu-web/dsh-metaphysics)';
750
750
 
751
751
  async function onlineLookup(text, { timeoutMs = 2500 } = {}) {
752
752
  if (typeof fetch !== 'function') return null;
@@ -1280,8 +1280,216 @@ const RULE_TABLE = RULES.reduce((acc, r) => { acc[r.name] = { cat: r.cat, luck:
1280
1280
  return { PILLAR_KEYS, PILLAR_LABEL, CATEGORY_ORDER, computeBaziShensha, RULE_TABLE };
1281
1281
  })();
1282
1282
 
1283
+ __mods.tiaohou = (function () {
1284
+
1285
+ const STEM_ELEMENT = {
1286
+ 甲: '木', 乙: '木', 丙: '火', 丁: '火', 戊: '土',
1287
+ 己: '土', 庚: '金', 辛: '金', 壬: '水', 癸: '水',
1288
+ };
1289
+
1290
+ const SEASON_TEMP = {
1291
+ 亥: -1.8, 子: -2, 丑: -1.5,
1292
+ 寅: -0.4, 卯: 0.2, 辰: 0.5,
1293
+ 巳: 1.3, 午: 2, 未: 1.5,
1294
+ 申: 0.6, 酉: 0.2, 戌: -0.2,
1295
+ };
1296
+
1297
+ const SEASON_NAME = {
1298
+ 亥: '初冬', 子: '仲冬', 丑: '季冬',
1299
+ 寅: '初春', 卯: '仲春', 辰: '季春',
1300
+ 巳: '初夏', 午: '仲夏', 未: '季夏',
1301
+ 申: '初秋', 酉: '仲秋', 戌: '季秋',
1302
+ };
1303
+
1304
+ const WET_BRANCH = { 丑: 1, 辰: 1, 子: 0.6, 亥: 0.5 };
1305
+ const DRY_BRANCH = { 未: 1, 戌: 1, 午: 0.4, 巳: 0.4 };
1306
+
1307
+ const NEED = {
1308
+ 寒湿: { element: '火', stem: '丙', avoid: '水', why: '冻土要太阳来解,水再多只会更冷' },
1309
+ 寒燥: { element: '火', stem: '丙', avoid: '水', why: '天寒地干,先要一点阳和之气' },
1310
+ 寒: { element: '火', stem: '丙', avoid: '水', why: '冬令气寒,非火不暖' },
1311
+ 温热: { element: '水', stem: '壬', avoid: '火', why: '火气初旺,得水润泽才好用' },
1312
+ 燥热: { element: '水', stem: '壬', avoid: '火', why: '火炎土燥,非水不润' },
1313
+ 热: { element: '水', stem: '壬', avoid: '火', why: '夏令炎威,先求一泓清水' },
1314
+ 湿滞: { element: '火', stem: '丙', avoid: '水', why: '湿气郁结,要火来蒸腾' },
1315
+ 燥: { element: '水', stem: '壬', avoid: '火', why: '气燥不润,得水则舒' },
1316
+ 平和: { element: null, stem: null, avoid: null, why: '寒暖相济,气候不是这一盘的主要矛盾' },
1317
+ };
1318
+
1319
+ const KIND_NAME = {
1320
+ 寒湿: '寒湿', 寒燥: '寒燥', 寒: '寒',
1321
+ 温热: '温热', 燥热: '燥热', 热: '热',
1322
+ 湿滞: '湿滞', 燥: '燥', 平和: '平和',
1323
+ };
1324
+
1325
+ const DAY_FEEL = {
1326
+ 寒湿: {
1327
+ 木: '木是花草藤萝,冰封的土里抽不出芽——它不缺雨水,缺的是一轮太阳',
1328
+ 火: '火在冬天最怕被水浇,一点火苗要护住,才谈得上发光',
1329
+ 土: '土冻成一块,再厚也长不出东西,得先晒透',
1330
+ 金: '金在寒水里泡久了,锋刃会发滞,要火来炼一炼',
1331
+ 水: '水本就冷,再加寒就是死水;要火把它烧活',
1332
+ },
1333
+ 寒燥: {
1334
+ 木: '木在干冷里最难熬,既缺暖气,又缺一点滋润',
1335
+ 火: '火在寒天里要先活下来,才有余力照别人',
1336
+ 土: '土冷而干,板结着,得暖气与一点水汽一起松',
1337
+ 金: '金寒则脆,得火炼、得土养,才成器',
1338
+ 水: '水在寒天里收得太紧,要一点火气化开',
1339
+ },
1340
+ 寒: {
1341
+ 木: '冬木先要暖,暖了才谈得上发荣',
1342
+ 火: '火在冬天要护住,别被冷风吹散',
1343
+ 土: '土寒不生物,先暖后养',
1344
+ 金: '金寒则钝,得火则利',
1345
+ 水: '水寒则滞,得火则行',
1346
+ },
1347
+ 温热: {
1348
+ 木: '木在暖和里长得快,但要防长得太急、根扎不深',
1349
+ 火: '火得时令,容易旺过头,要留一点水来收',
1350
+ 土: '土被火烤着,容易燥,得水润一润',
1351
+ 金: '金在暖处容易软,需要一点水土把它养住',
1352
+ 水: '水在暖处容易蒸干,要源头不断',
1353
+ },
1354
+ 燥热: {
1355
+ 木: '木被火烤着,叶子先焦,得先补水',
1356
+ 火: '火已经够旺了,再添柴只会烧到自己',
1357
+ 土: '土燥则裂,得水润、得木疏',
1358
+ 金: '金在燥热里容易发烫变形,要水来淬',
1359
+ 水: '水在燥热里最珍贵,一滴都不能浪费',
1360
+ },
1361
+ 热: {
1362
+ 木: '木在暑天要水,不然只长叶不结果',
1363
+ 火: '火已经当令,收着用比放出去更划算',
1364
+ 土: '土热则燥,得水则安',
1365
+ 金: '金在暑天要水来洗,才见光泽',
1366
+ 水: '水在暑天是命脉,要保住源头',
1367
+ },
1368
+ 湿滞: {
1369
+ 木: '木泡在水里会烂根,先要疏土透气',
1370
+ 火: '火在湿气里点不着,得先除湿',
1371
+ 土: '土湿成泥,得火蒸腾、得木来疏',
1372
+ 金: '金埋在湿土里会生锈,要见火见光',
1373
+ 水: '水已经太多,再添就是泛滥',
1374
+ },
1375
+ 燥: {
1376
+ 木: '木在燥气里容易枯,先要一点水',
1377
+ 火: '火在燥处容易失控,要收',
1378
+ 土: '土燥不毛,得水润、得木疏',
1379
+ 金: '金在燥处要水来洗,才不刺手',
1380
+ 水: '水在燥处最容易被耗干,要护住',
1381
+ },
1382
+ 平和: {
1383
+ 木: '寒暖还算相济,木有生长的余地',
1384
+ 火: '气候不偏,火可以按自己的节奏用',
1385
+ 土: '土不燥不湿,能养也能载',
1386
+ 金: '金不寒不燥,成器只差打磨',
1387
+ 水: '水不冰不涸,能流得动',
1388
+ },
1389
+ };
1390
+
1391
+ const round2 = (n) => Math.round(n * 100) / 100;
1392
+
1393
+ function judgeClimate({ monthBranch, dayStem, wuxing = {}, branches = [] }) {
1394
+ const fire = Number(wuxing['火'] || 0);
1395
+ const water = Number(wuxing['水'] || 0);
1396
+ let wet = 0;
1397
+ let dry = 0;
1398
+ let wetCount = 0;
1399
+ let dryCount = 0;
1400
+ for (const b of branches) {
1401
+ if (WET_BRANCH[b]) { wet += WET_BRANCH[b]; if (b === '丑' || b === '辰') wetCount += 1; }
1402
+ if (DRY_BRANCH[b]) { dry += DRY_BRANCH[b]; if (b === '未' || b === '戌') dryCount += 1; }
1403
+ }
1404
+ const seasonT = SEASON_TEMP[monthBranch] ?? 0;
1405
+ const temp = round2(seasonT + 0.45 * fire - 0.4 * water);
1406
+ const damp = round2(wet - dry + 0.25 * water - 0.25 * fire);
1407
+
1408
+ const cold = temp <= -0.8;
1409
+ const hot = temp >= 0.9;
1410
+ const wetSide = damp >= 0.8;
1411
+ const drySide = damp <= -0.8;
1412
+
1413
+ let kind = '平和';
1414
+ if (cold && wetSide) kind = '寒湿';
1415
+ else if (cold && drySide) kind = '寒燥';
1416
+ else if (cold) kind = '寒';
1417
+ else if (hot && drySide) kind = '燥热';
1418
+ else if (hot) kind = '温热';
1419
+ else if (hot && damp >= 0.8) kind = '湿滞';
1420
+ else if (drySide) kind = '燥';
1421
+ else if (wetSide) kind = '湿滞';
1422
+
1423
+ const need = NEED[kind] || NEED.平和;
1424
+ const dayElement = STEM_ELEMENT[dayStem] || '土';
1425
+ const evidence = [
1426
+ `${SEASON_NAME[monthBranch] || monthBranch}${monthBranch}月`,
1427
+ `火${fire}`,
1428
+ `水${water}`,
1429
+ wetCount ? `湿土${wetCount}处` : '',
1430
+ dryCount ? `燥土${dryCount}处` : '',
1431
+ ].filter(Boolean);
1432
+
1433
+ const priority = Math.abs(temp) >= 1.2 || Math.abs(damp) >= 1.2 ? '调候优先' : '扶抑为主';
1434
+ const narration = buildNarration({ kind, monthBranch, dayElement, need, temp, damp, fire, water });
1435
+
1436
+ return {
1437
+ kind,
1438
+ label: KIND_NAME[kind] || kind,
1439
+ temp,
1440
+ damp,
1441
+ cold,
1442
+ hot,
1443
+ wet: wetSide,
1444
+ dry: drySide,
1445
+ need: need.element ? { element: need.element, stem: need.stem, why: need.why } : null,
1446
+ avoidElement: need.avoid,
1447
+ dayElement,
1448
+ priority,
1449
+ evidence,
1450
+ narration,
1451
+ };
1452
+ }
1453
+
1454
+ function buildNarration({ kind, monthBranch, dayElement, need, fire, water }) {
1455
+ const feel = (DAY_FEEL[kind] || DAY_FEEL.平和)[dayElement] || '';
1456
+ const season = SEASON_NAME[monthBranch] || '';
1457
+ const head = `${season ? season : ''}${monthBranch}月出生,全局火${fire}、水${water},这一盘的气候是「${KIND_NAME[kind] || kind}」`;
1458
+ if (!need.element) {
1459
+ return `${head}。${feel}。调候不是这一盘的主要矛盾,取用仍以扶抑为主,寒暖只作微调。`;
1460
+ }
1461
+ return `${head}。${feel}。所以这一局要的不是更多的${kind.includes('寒') ? '水' : '火'},而是${need.stem}${need.element}——${need.why}。`;
1462
+ }
1463
+
1464
+ function arbitrate(climate, favors = [], avoids = []) {
1465
+ if (!climate || !climate.need) return { clash: false, text: '气候平和,按扶抑取用即可。' };
1466
+ const needEl = climate.need.element;
1467
+ const inFavor = favors.includes(needEl);
1468
+ const inAvoid = avoids.includes(needEl);
1469
+ const same = inFavor && !inAvoid;
1470
+ if (same) return { clash: false, text: `调候要${climate.need.stem}${needEl},扶抑也以${needEl}为喜——两套取法同向,不必取舍。` };
1471
+ return {
1472
+ clash: true,
1473
+ text: `调候要${climate.need.stem}${needEl},扶抑却把${needEl}列为${inAvoid ? '忌' : '闲'};两者不一致,本盘按调候优先取${needEl},扶抑次之——因为寒暖失衡时,再补强弱也难受。`,
1474
+ };
1475
+ }
1476
+
1477
+ function climateText(climate) {
1478
+ if (!climate) return '';
1479
+ const ev = (climate.evidence || []).join('、');
1480
+ const arb = climate.need
1481
+ ? `调候取${climate.need.stem}${climate.need.element}(${climate.need.why}),忌${climate.avoidElement}。`
1482
+ : '气候平和,调候不作主取。';
1483
+ return `${climate.label}(${ev})。${climate.narration}${arb}${climate.priority === '调候优先' ? ' 本盘调候优先于扶抑。' : ''}`;
1484
+ }
1485
+
1486
+ return { judgeClimate, arbitrate, climateText };
1487
+ })();
1488
+
1283
1489
  __mods.geju = (function () {
1284
1490
 
1491
+ const { judgeClimate, arbitrate } = __mods.tiaohou;
1492
+
1285
1493
  const STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
1286
1494
  const BRANCHES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];
1287
1495
 
@@ -1459,38 +1667,35 @@ function specialPatterns(pillars, dayStem, monthBranch, strength, wuxing, gods)
1459
1667
  return out;
1460
1668
  }
1461
1669
 
1462
- const TIAOHOU = {
1463
- 亥: ['火', '冬月寒水当令,最喜火暖局'],
1464
- 子: ['火', '仲冬水旺,最喜火暖局'],
1465
- 丑: ['火', '季冬湿寒,喜火解冻'],
1466
- 巳: ['水', '初夏火旺,喜水制衡'],
1467
- 午: ['水', '仲夏火炎,最喜水调候'],
1468
- 未: ['水', '季夏燥土,喜水润局'],
1469
- 寅: ['火', '初春尚寒,得火而发'],
1470
- 卯: ['火', '仲春木旺,喜火吐秀'],
1471
- 辰: ['金', '季春湿土,喜金水疏泄'],
1472
- 申: ['火', '初秋金旺,喜火炼金'],
1473
- 酉: ['火', '仲秋金锐,喜火制'],
1474
- 戌: ['水', '季秋燥土,喜水润泽'],
1475
- };
1476
-
1477
- function yongshenOf(dayStem, monthBranch, strength, wuxing) {
1670
+ function yongshenOf(dayStem, monthBranch, strength, wuxing, branches = []) {
1478
1671
  const roles = elementRoles(dayStem);
1479
1672
  const me = roles.me;
1480
1673
  const weak = strength.level === '身弱' || strength.level === '偏弱';
1481
1674
  const strong = strength.level === '身强' || strength.level === '偏强';
1482
1675
 
1483
- const favor = weak ? [roles.inMe, me] : strong ? [roles.shi, roles.cai, roles.guan] : [roles.inMe, me, roles.shi];
1484
- const avoid = weak ? [roles.shi, roles.cai, roles.guan] : strong ? [me, roles.inMe] : [roles.guan, roles.cai];
1485
- const favorableTenGods = weak ? ['正印', '偏印', '比肩', '劫财'] : strong
1486
- ? ['食神', '伤官', '正财', '偏财', '正官', '七杀']
1487
- : ['正印', '偏印', '食神', '伤官'];
1676
+ const baseFavor = weak ? [roles.inMe, me] : strong ? [roles.shi, roles.cai, roles.guan] : [roles.inMe, me, roles.shi];
1677
+ const baseAvoid = weak ? [roles.shi, roles.cai, roles.guan] : strong ? [me, roles.inMe] : [roles.guan, roles.cai];
1678
+ let favor = baseFavor.slice();
1679
+ let avoid = baseAvoid.slice();
1488
1680
 
1489
- const th = TIAOHOU[monthBranch];
1490
- const tiaohou = th ? { element: th[0], note: th[1] } : null;
1681
+ const climate = judgeClimate({ monthBranch, dayStem, wuxing, branches });
1682
+ const arb = arbitrate(climate, baseFavor, baseAvoid);
1683
+ if (climate.need && climate.priority === '调候优先') {
1684
+ const needEl = climate.need.element;
1685
+ if (!favor.includes(needEl)) favor.unshift(needEl);
1686
+ avoid = avoid.filter((e) => e !== needEl);
1687
+ if (climate.avoidElement && !avoid.includes(climate.avoidElement)) avoid.unshift(climate.avoidElement);
1688
+ }
1491
1689
 
1492
1690
  const roleName = (el) => (el === me ? '比劫' : el === roles.inMe ? '印'
1493
1691
  : el === roles.shi ? '食伤' : el === roles.cai ? '财' : '官杀');
1692
+ const expand = {
1693
+ 比劫: ['比肩', '劫财'], 印: ['正印', '偏印'], 食伤: ['食神', '伤官'],
1694
+ 财: ['正财', '偏财'], 官杀: ['正官', '七杀'],
1695
+ };
1696
+ const favorTenGods = Array.from(new Set(favor.flatMap((el) => expand[roleName(el)] || [])));
1697
+ const avoidTenGods = Array.from(new Set(avoid.flatMap((el) => expand[roleName(el)] || [])));
1698
+
1494
1699
  const detail = [
1495
1700
  `日主${dayStem}${me},${strength.level}(${strength.score} 分):`,
1496
1701
  weak
@@ -1498,24 +1703,22 @@ function yongshenOf(dayStem, monthBranch, strength, wuxing) {
1498
1703
  : strong
1499
1704
  ? `喜${roles.shi}(食伤)泄秀、${roles.cai}(财)耗、${roles.guan}(官杀)制;忌${me}(比劫)与${roles.inMe}(印)再助。`
1500
1705
  : '身中和,先取调候与通关,喜忌随大运流年动态变化。',
1501
- tiaohou ? `调候(简化):${tiaohou.note},宜${tiaohou.element}。` : '',
1502
- '扶抑法为主;调候未用穷通宝鉴全表,各派取用不同,仅作方向提示。',
1706
+ `调候:${climate.label}(${(climate.evidence || []).join('、')})${climate.need ? `,取${climate.need.stem}${climate.need.element},忌${climate.avoidElement}` : ',气候平和'}。`,
1707
+ arb.text,
1708
+ arb.clash ? '取舍:本盘按「调候优先、扶抑次之」取用;若你更认同扶抑派,可把调候当环境偏好,强弱判断不受影响。' : '',
1503
1709
  ].filter(Boolean).join('');
1504
1710
 
1505
1711
  return {
1506
- method: '扶抑为主 + 调候简化提示',
1712
+ method: climate.priority === '调候优先' ? '调候优先 + 扶抑校验' : '扶抑为主 + 调候校验',
1507
1713
  level: strength.level,
1508
1714
  favor,
1509
1715
  avoid,
1510
1716
  favorRoles: favor.map(roleName),
1511
1717
  avoidRoles: avoid.map(roleName),
1512
- favorTenGods: favorableTenGods,
1513
- avoidTenGods: weak
1514
- ? ['食神', '伤官', '正财', '偏财', '正官', '七杀']
1515
- : strong
1516
- ? ['比肩', '劫财', '正印', '偏印']
1517
- : ['正官', '七杀', '正财', '偏财'],
1518
- tiaohou,
1718
+ favorTenGods,
1719
+ avoidTenGods,
1720
+ tiaohou: { ...climate, ...arb, element: climate.need ? climate.need.element : null },
1721
+ climate,
1519
1722
  detail,
1520
1723
  };
1521
1724
  }
@@ -1534,33 +1737,54 @@ function scoreLuck(ganzhi, frame) {
1534
1737
  const branch = ganzhi[1];
1535
1738
  const stemEl = STEM_ELEMENT[stem];
1536
1739
  const branchEl = BRANCH_ELEMENT[branch];
1740
+ const th = ys.tiaohou || ys.climate || null;
1537
1741
  const scoreEl = (el) => {
1538
1742
  let s = 0;
1539
1743
  if (ys.favor.includes(el)) s += 1;
1540
1744
  if (ys.avoid.includes(el)) s -= 1;
1541
- if (ys.tiaohou && el === ys.tiaohou.element) s += 0.4;
1542
1745
  return s;
1543
1746
  };
1544
1747
  let score = scoreEl(stemEl) * 1.0 + scoreEl(branchEl) * 0.8;
1545
1748
  for (const h of (HIDDEN[branch] || []).slice(1)) {
1546
1749
  score += scoreEl(STEM_ELEMENT[h]) * 0.2;
1547
1750
  }
1548
- score = Math.round(score * 10) / 10;
1549
1751
 
1550
- const godStem = tenGod(frame.dayStem, stem);
1551
- const bonus = ys.favorTenGods.includes(godStem) ? 0.3 : 0;
1552
- const total = Math.round((score + bonus) * 10) / 10;
1553
-
1554
- const tier = TIERS.find(([min]) => total >= min)[1];
1555
1752
  const reasons = [];
1556
1753
  if (ys.favor.includes(stemEl)) reasons.push(`天干${stem}${stemEl}为用神`);
1557
1754
  else if (ys.avoid.includes(stemEl)) reasons.push(`天干${stem}${stemEl}为忌神`);
1558
1755
  else reasons.push(`天干${stem}${stemEl}不喜不忌`);
1559
1756
  if (ys.favor.includes(branchEl)) reasons.push(`地支${branch}${branchEl}助用`);
1560
1757
  else if (ys.avoid.includes(branchEl)) reasons.push(`地支${branch}${branchEl}助忌`);
1561
- if (ys.tiaohou && (stemEl === ys.tiaohou.element || branchEl === ys.tiaohou.element)) {
1562
- reasons.push(`合调候(${ys.tiaohou.element})`);
1758
+
1759
+ if (th && th.need && th.priority === '调候优先') {
1760
+ const needEl = th.need.element;
1761
+ const oppEl = th.avoidElement;
1762
+ const cold = String(th.kind).includes('寒');
1763
+ if (stemEl === needEl) {
1764
+ score += 1.1;
1765
+ reasons.push(`${th.label}之局得${stem}${stemEl},${cold ? '解冻' : '得润'}`);
1766
+ } else if (stemEl === oppEl) {
1767
+ score -= 0.9;
1768
+ reasons.push(`${th.label}之局再逢${stem}${stemEl},${cold ? '冻木难生' : '燥上加燥'}`);
1769
+ }
1770
+ if (branchEl === needEl) {
1771
+ score += 0.9;
1772
+ reasons.push(`地支${branch}${branchEl}合调候`);
1773
+ } else if (branchEl === oppEl) {
1774
+ score -= 1.0;
1775
+ reasons.push(`地支${branch}${branchEl}加重${th.label}`);
1776
+ }
1777
+ if (cold && (stemEl === '水' || branchEl === '水')) score -= 0.3;
1778
+ } else if (th && th.need && (stemEl === th.need.element || branchEl === th.need.element)) {
1779
+ reasons.push(`合调候(${th.need.element})`);
1563
1780
  }
1781
+
1782
+ const godStem = tenGod(frame.dayStem, stem);
1783
+ const bonus = ys.favorTenGods.includes(godStem) ? 0.3 : 0;
1784
+ let total = Math.round((score + bonus) * 10) / 10;
1785
+ total = Math.max(-4, Math.min(4, total));
1786
+
1787
+ const tier = TIERS.find(([min]) => total >= min)[1];
1564
1788
  return { ganzhi, score: total, tier, stemTenGod: godStem, reasons, note: `${godStem}运,${tier}(${total})` };
1565
1789
  }
1566
1790
 
@@ -1569,7 +1793,7 @@ function analyzeBaziFrame({ pillars, dayStem, monthBranch, strength, wuxing }) {
1569
1793
  const month = monthPattern(pillars, dayStem, monthBranch);
1570
1794
  const special = specialPatterns(pillars, dayStem, monthBranch, strength, wuxing, gods);
1571
1795
  const geju = [month, ...special];
1572
- const yongshen = yongshenOf(dayStem, monthBranch, strength, wuxing);
1796
+ const yongshen = yongshenOf(dayStem, monthBranch, strength, wuxing, Object.values(pillars).map((p) => p.branch));
1573
1797
  return {
1574
1798
  geju,
1575
1799
  primary: month,
@@ -2042,6 +2266,7 @@ function buildBazi(input) {
2042
2266
  },
2043
2267
  strength,
2044
2268
  frame,
2269
+ climate: frame.yongshen.climate || frame.yongshen.tiaohou || null,
2045
2270
  liunian,
2046
2271
  liunianFrom: thisYear,
2047
2272
  };
@@ -7276,6 +7501,7 @@ function baziInterpret(r) {
7276
7501
  const st = isObj(r.strength) ? r.strength : {};
7277
7502
  const frame = isObj(r.frame) ? r.frame : {};
7278
7503
  const ys = isObj(frame.yongshen) ? frame.yongshen : {};
7504
+ const cli = r.climate || (isObj(ys.climate) ? ys.climate : (isObj(ys.tiaohou) ? ys.tiaohou : null));
7279
7505
  const wx = isObj(r.wuxing) ? r.wuxing : {};
7280
7506
  const level = pick(st, 'level', '中和');
7281
7507
  const favor = Array.isArray(ys.favor) ? ys.favor : [];
@@ -7459,10 +7685,12 @@ function baziInterpret(r) {
7459
7685
  else if (!good.includes(curTier) && !good.includes(lnTier)) out.push('大运与流年都偏逆:以守住基本盘为主,减少新增承诺。');
7460
7686
  else out.push('大运与流年同向偏顺:可以把想做但一直拖着的事排上日程。');
7461
7687
  }
7462
- const tiao = ys.tiaohou && ys.tiaohou.element;
7463
- if (tiao) out.push(favor.includes(tiao)
7464
- ? `调候喜${tiao},与扶抑用神同向:取用上不打架,${tiao}相关的行业与环境优先。`
7465
- : `调候喜${tiao},不在扶抑的喜用里:两套取法有分歧,这里以扶抑为主,${tiao}只作环境上的小幅偏好。`);
7688
+ const th = ys.tiaohou && ys.tiaohou.need ? ys.tiaohou : null;
7689
+ if (th) {
7690
+ out.push(th.clash
7691
+ ? `调候要${th.need.stem}${th.need.element},扶抑不在喜用里:两套取法有分歧,本盘按调候优先——寒暖失衡时,再补强弱也难受。`
7692
+ : `调候要${th.need.stem}${th.need.element},与扶抑用神同向:取用上不打架,${th.need.element}相关的行业与环境优先。`);
7693
+ }
7466
7694
  return out.join(' ');
7467
7695
  })(),
7468
7696
  },
@@ -7471,6 +7699,12 @@ function baziInterpret(r) {
7471
7699
  text: `喜用:${join(favor)}(对应十神:${join(ys.favorTenGods || ys.favorRoles || [])});忌:${join(avoid)}(对应十神:${join(ys.avoidTenGods || ys.avoidRoles || [])})。` +
7472
7700
  `${pick(ys, 'detail', '')}`,
7473
7701
  },
7702
+ ...(cli ? [{
7703
+ key: 'climate', label: '寒暖燥湿',
7704
+ text: `${cli.narration}${cli.need
7705
+ ? `调候取${cli.need.stem}${cli.need.element},忌${cli.avoidElement};${cli.clash ? '与扶抑冲突,本盘以调候为先' : '与扶抑同向'}`
7706
+ : '气候平和,调候不作主取'}。`,
7707
+ }] : []),
7474
7708
  {
7475
7709
  key: 'geju', label: '格局依据',
7476
7710
  text: (Array.isArray(frame.geju) ? frame.geju : []).map((g) => `${g.name}(${g.kind}):${g.evidence}`).join(';') || '未取到格局',
@@ -7481,7 +7715,7 @@ function baziInterpret(r) {
7481
7715
  },
7482
7716
  {
7483
7717
  key: 'limits', label: '未纳入',
7484
- text: '本盘没有计算:流月与流日、神煞的加权轻重、地支藏干的动态引化(合冲后再论)。取用以扶抑为主、调候只做简化提示,各派取法不同;真太阳时未含历史时区与夏令时。把这些补上会改变"强弱"的边际判断,所以这里只给方向,不下断语。',
7718
+ text: '本盘没有计算:流月与流日、神煞的加权轻重、地支藏干的动态引化(合冲后再论)。取用按「调候优先、扶抑校验」;调候由月令与全局寒暖燥湿判定,未逐条录入穷通宝鉴 120 条,各派取法仍有分歧;真太阳时未含历史时区与夏令时。把这些补上会改变"强弱"的边际判断,所以这里只给方向,不下断语。',
7485
7719
  },
7486
7720
  ];
7487
7721
 
@@ -8943,6 +9177,7 @@ function baziText(r) {
8943
9177
  `   ${r.frame.geju.map((g) => `${g.name}[${g.kind}]`).join(' ')}`,
8944
9178
  `用神:喜${r.frame.yongshen.favor.join('')}(${r.frame.yongshen.favorTenGods.join('、')}) 忌${r.frame.yongshen.avoid.join('')}(${r.frame.yongshen.avoidTenGods.join('、')}) ${r.frame.yongshen.method}`,
8945
9179
  `   ${r.frame.yongshen.detail}`,
9180
+ `寒暖:${r.climate ? `${r.climate.label}(${(r.climate.evidence || []).join('、')})${r.climate.need ? ` 调候取${r.climate.need.stem}${r.climate.need.element} 忌${r.climate.avoidElement}` : ''}` : '—'}`,
8946
9181
  `十神权重:${Object.entries(r.frame.godStats.groups).map(([k, v]) => `${k}${v}`).join(' ')}`,
8947
9182
  ] : [];
8948
9183
  return [
@@ -10241,6 +10476,19 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
10241
10476
  @media print{.mp-cg{break-inside:avoid}}
10242
10477
  @media (max-width:640px){.mp-cg-w{grid-template-columns:repeat(2,minmax(0,1fr))}}
10243
10478
  .mp-quick-h{font-size:13px;color:var(--lu);margin-bottom:6px;font-family:system-ui,sans-serif}
10479
+ .mp-cli{margin:10px 0;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--card)}
10480
+ .mp-cli-h{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ink)}
10481
+ .mp-cli-h b{font-size:13px}
10482
+ .mp-cli-k{font-weight:700;color:var(--lu)}
10483
+ .mp-cli-p{margin-left:auto;font-size:11.5px;color:var(--quan);background:var(--bg);border:1px solid var(--line);border-radius:999px;padding:1px 8px}
10484
+ .mp-cli-bar{position:relative;margin:9px 0 4px;height:8px;border-radius:999px;background:linear-gradient(90deg,var(--quan) 0%,var(--line) 50%,var(--ji) 100%)}
10485
+ .mp-cli-bar i{position:absolute;top:-3px;width:14px;height:14px;margin-left:-7px;border-radius:50%;background:var(--card);border:2px solid var(--ink);box-shadow:0 0 0 2px var(--card)}
10486
+ .mp-cli-axis{display:flex;justify-content:space-between;font-size:11px;color:var(--ink3);margin-bottom:8px}
10487
+ .mp-cli-row{display:flex;flex-wrap:wrap;gap:6px 10px;align-items:center;font-size:12.5px;color:var(--ink2)}
10488
+ .mp-cli-row em{font-style:normal;color:var(--ink3)}
10489
+ .mp-cli-row b{color:var(--ink)}
10490
+ .mp-cli-narr{margin-top:8px;font-size:13px;line-height:1.85;color:var(--ink2);border-left:2px solid var(--quan);padding-left:9px}
10491
+ @media print{.mp-cli{break-inside:avoid}}
10244
10492
  .mp-quick-pre{margin:0;white-space:pre-wrap;word-break:break-word;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.9;color:var(--ink2)}
10245
10493
  .mp-al{margin:12px 16px;border:1px solid var(--line);border-radius:8px;background:var(--card);padding:12px 14px;font-family:system-ui,sans-serif}
10246
10494
  .mp-al-h{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;border-bottom:1px solid var(--hair);padding-bottom:8px;margin-bottom:9px}
@@ -11067,7 +11315,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
11067
11315
  const num = (v) => (typeof v === 'number' && isFinite(v) ? v : 0);
11068
11316
  const dyScore = (d) => (d.luck ? num(d.luck.score) : 0);
11069
11317
 
11070
- const VMAX = 3.2;
11318
+ const VMAX = 4.2;
11071
11319
  const VMIN = -2.2;
11072
11320
  const startAge = num(r.dayun.startAge && r.dayun.startAge.years);
11073
11321
  const dyEnd = dyList.length
@@ -11083,7 +11331,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
11083
11331
  const pw = W - M.l - M.r;
11084
11332
  const ph = H - M.t - M.b;
11085
11333
  const X = (age) => M.l + ((age - a0) / span) * pw;
11086
- const Y = (v) => M.t + ph - ((v - VMIN) / (VMAX - VMIN)) * ph;
11334
+ const Y = (v) => M.t + ph - ((Math.max(VMIN, Math.min(VMAX, v)) - VMIN) / (VMAX - VMIN)) * ph;
11087
11335
 
11088
11336
  const BANDS = [
11089
11337
  { from: 1.2, to: VMAX, cls: 'b-good' },
@@ -11408,6 +11656,21 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
11408
11656
  <div class="pp-tl">喜 ${fr.yongshen.favor.map(el).join('')} 忌 ${fr.yongshen.avoid.map(el).join('')} <span class="pp-dim">${esc(fr.yongshen.method)}</span></div>
11409
11657
  <div class="pp-chips">${fr.yongshen.favorTenGods.map((t) => `<span class="pp-chip ok">${esc(t)}</span>`).join('')}${fr.yongshen.avoidTenGods ? fr.yongshen.avoidTenGods.map((t) => `<span class="pp-chip warn">${esc(t)}</span>`).join('') : ''}</div>
11410
11658
  <div class="pp-tl pp-dim">${esc(fr.yongshen.detail)}</div>` : '';
11659
+ const cli = r.climate || (fr.yongshen && fr.yongshen.climate) || null;
11660
+ const cliCard = cli ? (() => {
11661
+ const pct = Math.max(2, Math.min(98, Math.round(((Number(cli.temp) || 0) + 3) / 6 * 100)));
11662
+ const need = cli.need ? `<em>调候取</em><b>${esc(cli.need.stem + cli.need.element)}</b>` : '<em>气候平和</em>';
11663
+ const avoid = cli.need ? `<em>忌</em><b>${esc(cli.avoidElement)}</b>` : '';
11664
+ const ev = (cli.evidence || []).length ? `<em>依据</em><span>${esc(cli.evidence.join('、'))}</span>` : '';
11665
+ const pri = cli.priority === '调候优先' ? '<span class="mp-cli-p">调候优先</span>' : '<span class="mp-cli-p">扶抑为主</span>';
11666
+ return `<section class="mp-cli" aria-label="寒暖燥湿">
11667
+ <div class="mp-cli-h"><b>寒暖燥湿</b><span class="mp-cli-k">${esc(cli.label || '')}</span>${pri}</div>
11668
+ <div class="mp-cli-bar" title="寒 ← → 热"><i style="left:${pct}%"></i></div>
11669
+ <div class="mp-cli-axis"><span>寒</span><span>平</span><span>热</span></div>
11670
+ <div class="mp-cli-row">${need}${avoid}${ev}</div>
11671
+ <div class="mp-cli-narr">${esc(cli.narration || '')}</div>
11672
+ </section>`;
11673
+ })() : '';
11411
11674
  const gods = fr.godStats ? `<div class="pp-chips">${Object.entries(fr.godStats.groups).map(([k, v]) => `<span class="pp-chip">${k} ${v}</span>`).join('')}</div>` : '';
11412
11675
 
11413
11676
  const dy = r.dayun.list.map((d) => {
@@ -11433,6 +11696,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
11433
11696
  ${str}
11434
11697
  ${sect('格局', gj)}
11435
11698
  ${sect('用神', ys)}
11699
+ ${cliCard}
11436
11700
  ${sect('五行与十神', `<div class="pp-chips">${wx}</div>${gods}`)}
11437
11701
  ${sect('大运', `${pp.curveHTML(r)}<div class="pp-chips">${dy}</div>`)}
11438
11702
  ${ln ? sect('流年', ln) : ''}
package/engine/bazi.js CHANGED
@@ -506,7 +506,8 @@ export function buildBazi(input) {
506
506
  list: dayun,
507
507
  },
508
508
  strength,
509
- frame,
509
+ frame,
510
+ climate: frame.yongshen.climate || frame.yongshen.tiaohou || null,
510
511
  liunian,
511
512
  liunianFrom: thisYear,
512
513
  };