dsh-metaphysics 0.65.0 → 0.67.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.
@@ -362,7 +362,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
362
362
  <div class="wrap">
363
363
  <header>
364
364
  <div class="brand-row">
365
- <div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.65.0</span><small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></span></div>
365
+ <div class="brand"><span class="seal" aria-hidden="true">命</span><span class="brand-txt">命理排盘<span class="ver">v0.67.0</span><small>八字 · 紫微 · 六爻 · 梅花 · 六壬 · 奇门 · 合盘 · 塔罗 全部在本机计算</small></span></div>
366
366
  <div class="view-switch">
367
367
  <span class="hint">熟练了可以换回平铺</span>
368
368
  <span class="seg" role="group" aria-label="首屏样式">
@@ -653,7 +653,7 @@ h3::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--li
653
653
  <h3>对拍:把典籍当期望值</h3>
654
654
  <ul><li>六爻:京房八宫卦序与世应,64 卦全表;旬空六旬表</li><li>六壬:日干寄宫、中气换将;紫微:纳音定五行局、紫微天府相照</li><li>卦例:《增删卜易》9 条 +《卜筮正宗》128 条(93 成对 + 35 静卦),核本变卦 / 动爻数 / 卦宫 / 缺爻 / 旬空</li><li>奇门:20 个时辰 × 9 宫,核四柱 / 局数 / 值符 / 值使 / 星门神 / 天盘干</li></ul>
655
655
  <h3>工程验证</h3>
656
- <ul><li>测试:165 个测试文件 / 9019 条断言;七道闸(回归 · 断言基线 · 测试可失败自检 · HTML 注入面 · 工程约定 · 产物宿主形态 · 随机扫射)</li><li>可复现:seed / asOf 显式;同一输入同一输出</li><li>口径:晚子时、真太阳时、奇门三流派、闰月归月都可切换,并有字段级差异对照</li></ul>
656
+ <ul><li>测试:170 个测试文件 / 9352 条断言;七道闸(回归 · 断言基线 · 测试可失败自检 · HTML 注入面 · 工程约定 · 产物宿主形态 · 随机扫射)</li><li>可复现:seed / asOf 显式;同一输入同一输出</li><li>口径:晚子时、真太阳时、奇门三流派、闰月归月都可切换,并有字段级差异对照</li></ul>
657
657
 
658
658
  <h3>已知边界(不猜)</h3>
659
659
  <ul><li>六爻应期(具体哪天应验)不做;卦例只录动爻个数,不录爻位</li><li>财富/健康只给结构判断与档位,不给金额区间、不作诊断</li><li>紫微飞星已做「单一支化逐宫追到成环」与「三方四正 16 条按落宫归堆」,但都未叠大限流年四化、不折吉凶;八字交运日已能算到日/时,但未与第三方排盘案例批量对拍</li></ul>
@@ -2752,7 +2752,10 @@ const YUEDE_HE = { 丙: '辛', 壬: '丁', 甲: '己', 庚: '乙' };
2752
2752
  const FUXING = {
2753
2753
  甲: ['寅', '子'], 丙: ['寅', '子'],
2754
2754
  乙: ['卯', '丑'], 癸: ['卯', '丑'],
2755
- 丁: ['酉'], 戊: ['申'], 己: ['未'], 庚: ['午'], 辛: ['巳'], 壬: ['辰'],
2755
+ // 丁取亥:本表所引《甲丙相邀入虎乡歌》原文作「戊猴己未丁宜亥」。
2756
+ // 旧表写丁酉,与自家所引歌诀对不上——酉是「丁酉」这个干支的干,不是亥的形讹,
2757
+ // 属后世把干支名误当查法所致。改从歌诀,并保留旧说于 rule 文本备查。
2758
+ 丁: ['亥'], 戊: ['申'], 己: ['未'], 庚: ['午'], 辛: ['巳'], 壬: ['辰'],
2756
2759
  };
2757
2760
  // 天官贵人(通行表,流派有异)
2758
2761
  const TIANGUAN = { 甲: ['未'], 乙: ['辰'], 丙: ['巳'], 丁: ['酉'], 戊: ['戌'], 己: ['卯'], 庚: ['亥'], 辛: ['申'], 壬: ['午'], 癸: ['寅'] };
@@ -2787,10 +2790,16 @@ const WANGSHEN = { 寅午戌: ['巳'], 申子辰: ['亥'], 巳酉丑: ['申'],
2787
2790
  const JINYU = { 甲: ['辰'], 乙: ['巳'], 丙: ['未'], 丁: ['申'], 戊: ['未'], 己: ['申'], 庚: ['戌'], 辛: ['亥'], 壬: ['丑'], 癸: ['寅'] };
2788
2791
  // 禄神
2789
2792
  const LUSHEN = { 甲: ['寅'], 乙: ['卯'], 丙: ['巳'], 丁: ['午'], 戊: ['巳'], 己: ['午'], 庚: ['申'], 辛: ['酉'], 壬: ['亥'], 癸: ['子'] };
2790
- // 羊刃:禄前一位(阳干论刃为主)
2791
- const YANGREN = { 甲: ['卯'], 乙: ['辰'], 丙: ['午'], 丁: ['未'], 戊: ['午'], 己: ['未'], 庚: ['酉'], 辛: ['戌'], 壬: ['子'], 癸: ['丑'] };
2792
- // 飞刃:羊刃六冲
2793
- const FEIREN = { 甲: ['酉'], 乙: ['戌'], 丙: ['子'], 丁: ['丑'], 戊: ['子'], 己: ['丑'], 庚: ['卯'], 辛: ['辰'], 壬: ['午'], 癸: ['未'] };
2793
+ // 羊刃(DeepSeek 派):帝旺本位,阴阳干都取「禄后一位」——即阳干帝旺、阴干亦帝旺。
2794
+ // 阳干:甲卯 丙午 戊午 庚酉 壬子(十二长生帝旺位,历代无争议)。
2795
+ // 阴干:乙寅 丁巳 己巳 辛申 癸亥(阴干逆行长生,帝旺在其长生进位,非禄前)。
2796
+ // 旧表把阴干取成禄前一位(乙辰 丁未 己未 辛戌 癸丑),那一位其实是阴干的「衰」;
2797
+ // 说「乙刃在辰」是宋以后禄命家把阳干式硬套到阴干的结果,与十二长生自相矛盾。
2798
+ const YANGREN = { 甲: ['卯'], 乙: ['寅'], 丙: ['午'], 丁: ['巳'], 戊: ['午'], 己: ['巳'], 庚: ['酉'], 辛: ['申'], 壬: ['子'], 癸: ['亥'] };
2799
+ // 羊刃六冲(由 YANGREN 逐干取对冲,勿手写,免两表再度走散)
2800
+ const FEIREN = Object.fromEntries(
2801
+ Object.entries(YANGREN).map(([stem, arr]) => [stem, arr.map((b) => BRANCHES[(BRANCHES.indexOf(b) + 6) % 12])]),
2802
+ );
2794
2803
  // 流霞(通行表)
2795
2804
  const LIUXIA = { 甲: ['酉'], 乙: ['戌'], 丙: ['未'], 丁: ['申'], 戊: ['巳'], 己: ['午'], 庚: ['辰'], 辛: ['卯'], 壬: ['亥'], 癸: ['寅'] };
2796
2805
 
@@ -2807,11 +2816,40 @@ const TIAN_SHE = { 春: '戊寅', 夏: '甲午', 秋: '戊申', 冬: '甲子' };
2807
2816
  const SIFEI = { 春: ['庚申', '辛酉'], 夏: ['壬子', '癸亥'], 秋: ['甲寅', '乙卯'], 冬: ['丙午', '丁巳'] };
2808
2817
  // 童子煞:春秋生见寅子,冬夏生见卯未辰
2809
2818
  const TONGZI = { 春: ['寅', '子'], 秋: ['寅', '子'], 夏: ['卯', '未', '辰'], 冬: ['卯', '未', '辰'] };
2819
+ // 童子煞(纳音法,与季节法并行):金木命见午卯、水火命见酉戌、土命见辰巳
2820
+ // 口诀作「金木马卯合,水火鸡犬多,土命逢辰巳」——马=午、鸡=酉、犬=戌。
2821
+ // 旧实现只做季节法,把纳音法写作「流派多歧,仅作参考」,等于漏了一半查法。
2822
+ const TONGZI_NAYIN = { 金: ['午', '卯'], 木: ['午', '卯'], 水: ['酉', '戌'], 火: ['酉', '戌'], 土: ['辰', '巳'] };
2810
2823
  // 三奇贵人(须依序相连)
2811
2824
  const SANQI = ['甲戊庚', '乙丙丁', '壬癸辛'];
2812
2825
  // 金神:时柱见之
2813
2826
  const JINSHEN = ['乙丑', '己巳', '癸酉'];
2814
2827
 
2828
+ // ── 问真神煞大全补缺批(0.66):口径全部按《问真神煞大全》55 章实读钉死 ──
2829
+
2830
+ // 天德合:天德之干五合/支六合(寅月天德丁→壬合…)
2831
+ const TIANDE_HE = { 寅: '壬', 卯: '巳', 辰: '丁', 巳: '丙', 午: '寅', 未: '己', 申: '戊', 酉: '亥', 戌: '辛', 亥: '庚', 子: '申', 丑: '乙' };
2832
+ // 血刃:按月支查支
2833
+ const XUEYREN = { 寅: '丑', 卯: '未', 辰: '寅', 巳: '申', 午: '卯', 未: '酉', 申: '辰', 酉: '戌', 戌: '巳', 亥: '亥', 子: '午', 丑: '子' };
2834
+ // 红艳煞:日干查支
2835
+ const HONGYAN = { 甲: ['午'], 乙: ['午'], 丙: ['寅'], 丁: ['未'], 戊: ['辰'], 己: ['辰'], 庚: ['戌'], 辛: ['酉'], 壬: ['子'], 癸: ['申'] };
2836
+ // 孤鸾煞:日柱
2837
+ const GUALUAN = ['甲寅', '乙巳', '丙午', '丁巳', '戊午', '戊申', '辛亥', '壬子'];
2838
+ // 十灵日:日柱
2839
+ const SHILING = ['甲辰', '乙亥', '丙辰', '丁酉', '戊午', '庚戌', '庚寅', '辛亥', '壬寅', '癸未'];
2840
+ // 八专:日柱
2841
+ const BAZHUAN = ['甲寅', '乙卯', '丁未', '戊戌', '己未', '庚申', '辛酉', '癸丑'];
2842
+ // 九丑:日柱
2843
+ const JIUCHOU = ['丁酉', '戊子', '戊午', '己卯', '己酉', '辛卯', '辛酉', '壬子', '壬午'];
2844
+ // 天转:寅卯辰月乙卯、巳午未月丙午、申酉戌月辛酉、亥子丑月壬子(日柱)
2845
+ const TIANZH = { 春: '乙卯', 夏: '丙午', 秋: '辛酉', 冬: '壬子' };
2846
+ // 地转:春辛卯、夏戊午、秋癸酉、冬丙子(日柱)
2847
+ const DIZH = { 春: '辛卯', 夏: '戊午', 秋: '癸酉', 冬: '丙子' };
2848
+ // 学堂(纳音长生查法,问真采用第一种):年纳音五行 → 支
2849
+ const XUETANG = { 金: '巳', 木: '亥', 水: '申', 土: '申', 火: '寅' };
2850
+ // 词馆(纳音临官查法):年纳音五行 → 支
2851
+ const CIGUAN = { 金: '申', 木: '寅', 水: '亥', 土: '亥', 火: '巳' };
2852
+
2815
2853
  // ── 规则工厂 ────────────────────────────────────────────────────
2816
2854
 
2817
2855
  /** 天干查支:天乙、太极、文昌、福星、天官、国印、天厨、禄神、羊刃、飞刃、金舆、流霞 */
@@ -2884,8 +2922,16 @@ const RULES = [
2884
2922
  const he = k && YUEDE[k] ? YUEDE_HE[YUEDE[k]] : null;
2885
2923
  return he ? [S(he)] : [];
2886
2924
  }),
2925
+ byMonth('天德合', '贵人', 'good',
2926
+ '天德之合:寅月丁德→壬合、卯月申→巳、辰月壬→丁、巳月辛→丙、午月亥→寅、未月甲→己、申月癸→戊、酉月寅→亥、戌月丙→辛、亥月乙→庚、子月巳→申、丑月庚→乙(月支查干或支;无天德时天德合同样起作用)',
2927
+ (ctx) => {
2928
+ const ch = TIANDE_HE[ctx.pillars.month.branch];
2929
+ if (!ch) return [];
2930
+ return STEMS_LIST.includes(ch) ? [S(ch)] : [T(ch)];
2931
+ }),
2887
2932
  byStem('福星贵人', '贵人', 'good',
2888
- '甲丙见寅子,乙癸见卯丑,丁见酉、戊见申、己见未、庚见午、辛见巳、壬见辰(年干、日干查四支)',
2933
+ '甲丙见寅子,乙癸见卯丑,戊见申、己见未、丁见亥、庚见午、辛见巳、壬见辰(年干、日干查四支)。'
2934
+ + '出自《甲丙相邀入虎乡歌》「戊猴己未丁宜亥」;旧本有作丁见酉者,与歌诀不合,本插件从歌诀',
2889
2935
  FUXING, ['year', 'day']),
2890
2936
  byStem('天官贵人', '贵人', 'good',
2891
2937
  '甲未、乙辰、丙巳、丁酉、戊戌、己卯、庚亥、辛申、壬午、癸寅(年干、日干查四支;此表流派有异)',
@@ -2946,26 +2992,61 @@ const RULES = [
2946
2992
  byStem('金舆', '婚姻', 'good',
2947
2993
  '禄前二位:甲龙乙蛇丙戊羊、丁己申宫庚犬乡、辛猪壬牛癸虎位(日干查四支)',
2948
2994
  JINYU, ['day']),
2995
+ byStem('红艳煞', '婚姻', 'neutral',
2996
+ '甲乙午、丙寅、丁未、戊己辰、庚戌、辛酉、壬子、癸申(日干查四支)',
2997
+ HONGYAN, ['day']),
2998
+ byPillarGz('孤鸾煞', '婚姻', 'bad',
2999
+ '日柱甲寅、乙巳、丙午、丁巳、戊午、戊申、辛亥、壬子(日柱见之;又名呻吟煞)',
3000
+ GUALUAN),
3001
+ // 勾绞煞:桃花六冲之位,阳男阴女命前三辰为勾、后三辰为绞;阴男阳女反之
3002
+ byRefBranch('勾绞煞', '婚姻', 'bad',
3003
+ '桃花六冲之位:子见卯酉、丑见辰戌、寅见巳亥……(年支查余三支;阳男阴女命前三辰为勾后三为绞,阴男阳女反之)',
3004
+ (ctx) => {
3005
+ const idx = BRANCHES.indexOf(ctx.pillars.year.branch);
3006
+ const qian = BRANCHES[(idx + 3) % 12];
3007
+ const hou = BRANCHES[(idx + 9) % 12];
3008
+ const gouxian = ctx.gender === 'male'
3009
+ ? ((idx % 2) === 0) // 阳男:命前为勾
3010
+ : ((idx % 2) === 1); // 阴女:命前为勾
3011
+ return gouxian
3012
+ ? [{ kind: 'branch', ch: qian, label: '勾' }, { kind: 'branch', ch: hou, label: '绞' }]
3013
+ : [{ kind: 'branch', ch: hou, label: '勾' }, { kind: 'branch', ch: qian, label: '绞' }];
3014
+ }),
3015
+ // 元辰:阳男阴女年支后一辰冲位、阴男阳女前一辰冲位(问真:阳男阴女子年未…阴男阳女子年巳…)
3016
+ byRefBranch('元辰', '凶煞', 'bad',
3017
+ '阳男阴女:子见未、丑见申、寅见酉……(年支次一位的对冲);阴男阳女:子见巳、丑见午……(年支退一位的对冲)(年支查余三支;又名毛头星、大耗)',
3018
+ (ctx) => {
3019
+ const idx = BRANCHES.indexOf(ctx.pillars.year.branch);
3020
+ const yangNan = ctx.gender === 'male'
3021
+ ? ((idx % 2) === 0)
3022
+ : ((idx % 2) === 1);
3023
+ const base = yangNan ? (idx + 1) % 12 : (idx + 11) % 12;
3024
+ return [T(BRANCHES[(base + 6) % 12])];
3025
+ }),
2949
3026
 
2950
3027
  // 性情
2951
3028
  byTrio('华盖', '性情', 'neutral',
2952
3029
  '寅午戌见戌、申子辰见辰、巳酉丑见丑、亥卯未见未(年支、日支双查)',
2953
3030
  HUAGAI),
2954
3031
  byStem('羊刃', '性情', 'bad',
2955
- '禄前一位:甲卯、乙辰、丙戊午、丁己未、庚酉、辛戌、壬子、癸丑(日干查四支;阳干论刃为主)',
3032
+ '帝旺之位:甲卯、乙寅、丙午、丁巳、戊午、己巳、庚酉、辛申、壬子、癸亥(日干查四支)。'
3033
+ + '旧本把阴干记作禄前一位(乙辰、丁未、己未、辛戌、癸丑),那一位实为阴干之「衰」,与十二长生自相矛盾,本插件不取',
2956
3034
  YANGREN, ['day']),
2957
3035
  byStem('飞刃', '性情', 'bad',
2958
- '羊刃六冲:甲酉、乙戌、丙子、丁丑、戊子、己丑、庚卯、辛辰、壬午、癸未(日干查四支)',
3036
+ '羊刃六冲(由羊刃位逐干对冲推得,不另立表):甲酉、乙申、丙子、丁亥、戊子、己亥、庚卯、辛寅、壬午、癸巳(日干查四支)',
2959
3037
  FEIREN, ['day']),
2960
3038
  byPillarGz('魁罡', '性情', 'neutral',
2961
3039
  '日柱庚辰、庚戌、壬辰、戊戌(日柱见之)',
2962
3040
  KUIGANG),
2963
3041
  byMonth('童子煞', '性情', 'neutral',
2964
- '春秋生见寅子,冬夏生见卯未辰(取季节口诀,查日支、时支;另有纳音五行一法,流派多歧,仅作参考)',
3042
+ '两法并行:①季节法——春秋生见寅子,冬夏生见卯未辰(查日支、时支);'
3043
+ + '②纳音法——金木命见午卯,水火命见酉戌,土命见辰巳(年柱纳音查日支、时支)。任一中即算',
2965
3044
  (ctx) => {
3045
+ const set = new Set();
2966
3046
  const season = SEASON[ctx.pillars.month.branch];
2967
- const list = season && TONGZI[season];
2968
- return list ? list.map(T) : [];
3047
+ for (const b of (season && TONGZI[season]) || []) set.add(b);
3048
+ for (const b of TONGZI_NAYIN[ctx.nayinElement] || []) set.add(b);
3049
+ return [...set].map(T);
2969
3050
  }, ['day', 'hour']),
2970
3051
  byPillarGz('六秀日', '性情', 'good',
2971
3052
  '日柱丙午、丁未、戊子、戊午、己丑、己未(日柱见之)',
@@ -2976,6 +3057,15 @@ const RULES = [
2976
3057
  byPillarGz('日贵', '性情', 'good',
2977
3058
  '日柱丁酉、丁亥、癸巳、癸卯(日柱见之)',
2978
3059
  RIGUI),
3060
+ byPillarGz('十灵日', '性情', 'good',
3061
+ '日柱甲辰、乙亥、丙辰、丁酉、戊午、庚戌、庚寅、辛亥、壬寅、癸未(日柱见之;「男带十灵好文章,女带十灵好衣裳」)',
3062
+ SHILING),
3063
+ byPillarGz('八专', '性情', 'neutral',
3064
+ '日柱甲寅、乙卯、丁未、戊戌、己未、庚申、辛酉、癸丑(日柱见之;干支同气坐禄或冠带)',
3065
+ BAZHUAN),
3066
+ byPillarGz('九丑', '性情', 'neutral',
3067
+ '日柱丁酉、戊子、戊午、己卯、己酉、辛卯、辛酉、壬子、壬午(日柱见之;「丑」指名声风评非容貌)',
3068
+ JIUCHOU),
2979
3069
 
2980
3070
  // 事业
2981
3071
  byStem('禄神', '事业', 'good',
@@ -3000,10 +3090,19 @@ const RULES = [
3000
3090
  WANGSHEN),
3001
3091
  {
3002
3092
  name: '空亡', cat: '凶煞', luck: 'bad',
3003
- rule: '以日柱所在旬的空亡反查各柱地支(日柱旬空)',
3093
+ // 日柱旬空为古法正传;年柱旬空另有一派(以年柱所在旬的空亡查余三支),
3094
+ // 两派所据都是「本旬无支可用」,逻辑同构,故并列而不取此舍彼。
3095
+ rule: '以日柱所在旬的空亡反查各柱地支(日柱旬空,主法);另有年柱旬空一派,一并标出',
3004
3096
  refs: ['day'], refKind: 'branch', viaLabel: '日柱旬空',
3005
3097
  targets: (ctx) => (ctx.kongwang || []).map(T),
3006
3098
  },
3099
+ {
3100
+ name: '年空', cat: '凶煞', luck: 'bad',
3101
+ rule: '以年柱所在旬的空亡反查其余三支(年柱旬空;古法多取日柱旬空,此派并存,命中单独标注)',
3102
+ refs: ['year'], refKind: 'branch', viaLabel: '年柱旬空',
3103
+ slots: ['month', 'day', 'hour'],
3104
+ targets: (ctx) => (ctx.yearKongwang || []).map(T),
3105
+ },
3007
3106
  byPillarGz('十恶大败', '凶煞', 'bad',
3008
3107
  '日柱甲辰、乙巳、丙申、丁亥、戊戌、己丑、庚辰、辛巳、壬申、癸亥(日柱见之)',
3009
3108
  SHIE_DABAI),
@@ -3020,6 +3119,30 @@ const RULES = [
3020
3119
  byStem('流霞', '凶煞', 'bad',
3021
3120
  '甲酉、乙戌、丙未、丁申、戊巳、己午、庚辰、辛卯、壬亥、癸寅(日干查四支;通行表)',
3022
3121
  LIUXIA, ['day']),
3122
+ byMonth('血刃', '凶煞', 'bad',
3123
+ '寅月丑、卯月未、辰月寅、巳月申、午月卯、未月酉、申月辰、酉月戌、戌月巳、亥月亥、子月午、丑月子(月支查四支)',
3124
+ (ctx) => {
3125
+ const ch = XUEYREN[ctx.pillars.month.branch];
3126
+ return ch ? [T(ch)] : [];
3127
+ }),
3128
+ byRefBranch('丧门', '凶煞', 'bad',
3129
+ '年支前两位:子见寅、丑见卯……(年支查余三支)',
3130
+ (ctx) => {
3131
+ const idx = BRANCHES.indexOf(ctx.pillars.year.branch);
3132
+ return [T(BRANCHES[(idx + 2) % 12])];
3133
+ }),
3134
+ byRefBranch('吊客', '凶煞', 'bad',
3135
+ '年支后两位:子见戌、丑见亥……(年支查余三支)',
3136
+ (ctx) => {
3137
+ const idx = BRANCHES.indexOf(ctx.pillars.year.branch);
3138
+ return [T(BRANCHES[(idx + 10) % 12])];
3139
+ }),
3140
+ byRefBranch('披麻', '凶煞', 'bad',
3141
+ '年支后三位:子见酉、丑见戌……(年支查余三支)',
3142
+ (ctx) => {
3143
+ const idx = BRANCHES.indexOf(ctx.pillars.year.branch);
3144
+ return [T(BRANCHES[(idx + 9) % 12])];
3145
+ }),
3023
3146
 
3024
3147
  // 格局
3025
3148
  byMonth('天赦日', '格局', 'good',
@@ -3032,15 +3155,55 @@ const RULES = [
3032
3155
  byPillarGz('金神', '格局', 'neutral',
3033
3156
  '时柱乙丑、己巳、癸酉(时柱见之;严格成格另需日主身旺,此仅记星)',
3034
3157
  JINSHEN, 'hour'),
3158
+ // 拱禄:五日五时,日时同干、虚拱禄支(癸亥日癸丑时拱子、癸丑日癸亥时拱子、丁巳日丁未时拱午、己未日己巳时拱午、戊辰日戊午时拱巳)
3159
+ {
3160
+ name: '拱禄', cat: '格局', luck: 'good',
3161
+ rule: '日时同干而禄位虚拱:癸亥日癸丑时、癸丑日癸亥时(拱子),丁巳日丁未时、己未日己巳时(拱午),戊辰日戊午时(拱巳);只宜虚拱,忌填实空亡',
3162
+ custom: (ctx) => {
3163
+ const GONG = { '癸亥|癸丑': '子', '癸丑|癸亥': '子', '丁巳|丁未': '午', '己未|己巳': '午', '戊辰|戊午': '巳' };
3164
+ const k = `${ctx.pillars.day.ganzhi}|${ctx.pillars.hour.ganzhi}`;
3165
+ return GONG[k] ? [{ pillars: ['day', 'hour'], via: '日时', target: GONG[k] }] : [];
3166
+ },
3167
+ },
3168
+ // 天转 / 地转:以月支定季节查日柱(五行旺极之日,盛极而衰)
3169
+ byMonth('天转', '凶煞', 'bad',
3170
+ '春乙卯、夏丙午、秋辛酉、冬壬子(月支定季节查日柱;「春兔夏马天地转,秋鸡冬鼠便为殃」)',
3171
+ (ctx) => {
3172
+ const season = SEASON[ctx.pillars.month.branch];
3173
+ const gz = ctx.pillars.day.ganzhi;
3174
+ return season && TIANZH[season] === gz ? [GZ(gz)] : [];
3175
+ }, ['day']),
3176
+ byMonth('地转', '凶煞', 'bad',
3177
+ '春辛卯、夏戊午、秋癸酉、冬丙子(月支定季节查日柱)',
3178
+ (ctx) => {
3179
+ const season = SEASON[ctx.pillars.month.branch];
3180
+ const gz = ctx.pillars.day.ganzhi;
3181
+ return season && DIZH[season] === gz ? [GZ(gz)] : [];
3182
+ }, ['day']),
3183
+ // 学堂 / 词馆:年柱纳音五行的长生 / 临官之支(问真采用禄命法第一种;正学堂另需干支同见,此仅记支)
3184
+ {
3185
+ name: '学堂', cat: '文星', luck: 'good',
3186
+ rule: '年纳音五行之长生:金见巳、木见亥、水见申、土见申、火见寅(年纳音查月日时支;学堂为纳音长生,主人聪明文才出众)',
3187
+ refs: ['year'], refKind: 'branch', viaLabel: '年纳音', slots: ['month', 'day', 'hour'],
3188
+ targets: (ctx) => [T(XUETANG[ctx.nayinElement] || '')].filter((t) => t.ch),
3189
+ },
3190
+ {
3191
+ name: '词馆', cat: '文星', luck: 'good',
3192
+ rule: '年纳音五行之临官:金见申、木见寅、水见亥、土见亥、火见巳(年纳音查月日时支;词馆为纳音临官,主文章学识)',
3193
+ refs: ['year'], refKind: 'branch', viaLabel: '年纳音', slots: ['month', 'day', 'hour'],
3194
+ targets: (ctx) => [T(CIGUAN[ctx.nayinElement] || '')].filter((t) => t.ch),
3195
+ },
3035
3196
  {
3036
3197
  name: '天罗', cat: '凶煞', luck: 'bad',
3037
- rule: '四支见戌、亥俱全(戌亥为天罗)',
3038
- custom: (ctx) => chartPattern(ctx, ['戌', '亥']),
3198
+ rule: '戌亥为天罗。法一以年支/日支查余三支:戌见亥、亥见戌即算,不要求四支俱全;'
3199
+ + '法二以年柱纳音查日支:火命见戌或亥。两法任一成立即命中(男忌天罗)',
3200
+ custom: (ctx) => luowangPair(ctx, '戌', '亥', '天罗', ['火']),
3039
3201
  },
3040
3202
  {
3041
3203
  name: '地网', cat: '凶煞', luck: 'bad',
3042
- rule: '四支见辰、巳俱全(辰巳为地网)',
3043
- custom: (ctx) => chartPattern(ctx, ['辰', '巳']),
3204
+ rule: '辰巳为地网。法一以年支/日支查余三支:辰见巳、巳见辰即算,不要求四支俱全;'
3205
+ + '法二以年柱纳音查日支:水命、土命见辰或巳。两法任一成立即命中(女忌地网)',
3206
+ custom: (ctx) => luowangPair(ctx, '辰', '巳', '地网', ['水', '土']),
3044
3207
  },
3045
3208
  {
3046
3209
  name: '三奇贵人', cat: '格局', luck: 'good',
@@ -3056,11 +3219,29 @@ const RULES = [
3056
3219
  },
3057
3220
  ];
3058
3221
 
3059
- /** 四支俱全即命中(天罗地网) */
3060
- function chartPattern(ctx, branches) {
3061
- const keys = PILLAR_KEYS.filter((k) => branches.includes(ctx.pillars[k].branch));
3062
- if (keys.length < branches.length) return [];
3063
- return [{ pillars: keys, via: '四支', target: branches.join('') }];
3222
+ /**
3223
+ * 天罗地网:两法并行,任一成立即命中。
3224
+ * 法一(主):以年支/日支查余三支——戌见亥、亥见戌为天罗;辰见巳、巳见辰为地网。只需两支成对,
3225
+ * 不要求四支俱全(旧实现要求「戌亥俱全」,四支里必须同时出现戌与亥,漏掉大半)。
3226
+ * 法二(辅):以年柱纳音查日支——火命见戌或亥为天罗,水命、土命见辰或巳为地网,金木二命无。
3227
+ * 命中时把「起查柱」与「应柱」都标出来,否则只看天罗在亥那一柱,读盘时找不到起因。
3228
+ */
3229
+ function luowangPair(ctx, a, b, label, nayinEls) {
3230
+ const out = [];
3231
+ // 法一:以年/日支查余三支(只需两支成对)
3232
+ for (const ref of ['year', 'day']) {
3233
+ const rb = ctx.pillars[ref].branch;
3234
+ const want = rb === a ? b : rb === b ? a : null;
3235
+ if (!want) continue;
3236
+ const hits = PILLAR_KEYS.filter((k) => k !== ref && ctx.pillars[k].branch === want);
3237
+ for (const k of hits) out.push({ pillars: [ref, k], via: BRANCH_VIA[ref], target: want });
3238
+ }
3239
+ // 法二:以年纳音查日支
3240
+ if (nayinEls.includes(ctx.nayinElement) && (ctx.pillars.day.branch === a || ctx.pillars.day.branch === b)) {
3241
+ out.push({ pillars: ['day'], via: `年纳音${ctx.nayinElement}`, target: ctx.pillars.day.branch });
3242
+ }
3243
+ void label;
3244
+ return out;
3064
3245
  }
3065
3246
 
3066
3247
  // ── 执行 ────────────────────────────────────────────────────────
@@ -3092,12 +3273,19 @@ function runRule(r, ctx) {
3092
3273
  * 计算八字神煞
3093
3274
  * @param {object} pillars { year, month, day, hour },每柱需有 stem/branch/ganzhi
3094
3275
  * @param {string[]} kongwang 日柱旬空的两个地支
3276
+ * @param {object} [opts] { gender?: 'male'|'female', yearNayinElement?: string }
3277
+ * gender 供勾绞煞 / 元辰辨阴阳男女;yearNayinElement 供学堂 / 词馆(年柱纳音五行)
3095
3278
  * @returns {{ detail: object, groups: array, names: string[], count: number }}
3096
3279
  * detail[key] = [{ name, cat, luck, via, target, rule }]
3097
3280
  * groups = [{ cat, items: [{ name, luck, pillars, via, target, rule }] }]
3098
3281
  */
3099
- function computeBaziShensha(pillars, kongwang = []) {
3100
- const ctx = { pillars, kongwang };
3282
+ function computeBaziShensha(pillars, kongwang = [], opts = {}) {
3283
+ const ctx = {
3284
+ pillars, kongwang,
3285
+ gender: opts.gender,
3286
+ nayinElement: opts.yearNayinElement,
3287
+ yearKongwang: opts.yearKongwang || [],
3288
+ };
3101
3289
  const items = [];
3102
3290
  for (const r of RULES) {
3103
3291
  const hits = runRule(r, ctx);
@@ -5239,6 +5427,196 @@ function weightPctOf(pillars = {}, { hourUnknown = false } = {}) {
5239
5427
  return { PILLAR_WEIGHT, HIDDEN_PCT, supportOf, branchStructureOf, weightPctOf };
5240
5428
  })();
5241
5429
 
5430
+ __mods.hehua = (function () {
5431
+ // 天干五合的「合化」判定。
5432
+ //
5433
+ // bazi.js 的 buildRelations 在干支关系层只写「有合、化某待定」——那一层不该断言化与不化。
5434
+ // 是否真化要过问真《基础知识·干支中》给的四条件:
5435
+ // ① 天干紧挨(隔一位=隔合、隔两位=遥合,都不化;争合、妒合一律不化)
5436
+ // ② 被化天干(阴干一侧)在天干上无同类(比劫)帮扶
5437
+ // ③ 月令有引化物(月支五行或月支本气=化神五行)
5438
+ // ④ 引化物不被克(克化神之五行不现于月干、日干,月支本气也不是它)
5439
+ //
5440
+ // 判完只作只读标注:不改旺衰分、不改五行权重、不改喜忌、不改 relations.stems 的文案。
5441
+ // 反化(甲己化木、乙庚化木、丙辛化火或金、丁壬化火或水、戊癸化土或水)诸家分歧大,本插件不做。
5442
+
5443
+ const STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
5444
+ const STEM_ELEMENT = {
5445
+ 甲: '木', 乙: '木', 丙: '火', 丁: '火', 戊: '土', 己: '土', 庚: '金', 辛: '金', 壬: '水', 癸: '水',
5446
+ };
5447
+ const BRANCH_ELEMENT = {
5448
+ 子: '水', 丑: '土', 寅: '木', 卯: '木', 辰: '土', 巳: '火',
5449
+ 午: '火', 未: '土', 申: '金', 酉: '金', 戌: '土', 亥: '水',
5450
+ };
5451
+ const OVERCOMES = { 木: '土', 土: '水', 水: '火', 火: '金', 金: '木' };
5452
+ const HIDDEN = {
5453
+ 子: ['癸'], 丑: ['己', '癸', '辛'], 寅: ['甲', '丙', '戊'], 卯: ['乙'],
5454
+ 辰: ['戊', '乙', '癸'], 巳: ['丙', '庚', '戊'], 午: ['丁', '己'], 未: ['己', '丁', '乙'],
5455
+ 申: ['庚', '壬', '戊'], 酉: ['辛'], 戌: ['戊', '辛', '丁'], 亥: ['壬', '甲'],
5456
+ };
5457
+ const STEM_HE = { 甲己: '土', 乙庚: '金', 丙辛: '水', 丁壬: '木', 戊癸: '火' };
5458
+ const KEYS = ['year', 'month', 'day', 'hour'];
5459
+ const LABEL = { year: '年', month: '月', day: '日', hour: '时' };
5460
+
5461
+ const METHOD = '问真《基础知识·干支中》:五合是否真化看四条件——天干紧挨、被化天干无同类帮扶、'
5462
+ + '月令有引化物、引化物不被克;隔合、遥合、争合、妒合一律不化';
5463
+ const BOUNDARY = '只作只读标注:不改旺衰分、不改五行权重、不改喜忌。'
5464
+ + '争合=两阳干争一阴干,妒合=两阴干争一阳干,问真说这两者「实际指的就是合绊」,故判不化。';
5465
+
5466
+ const isYangStem = (stem) => STEMS.indexOf(stem) % 2 === 0;
5467
+ const heOf = (a, b) => STEM_HE[a + b] || STEM_HE[b + a] || null;
5468
+ const elOf = (stem) => STEM_ELEMENT[stem] || '';
5469
+ /** 克某五行的那一行 */
5470
+ const keOf = (element) => Object.keys(OVERCOMES).find((el) => OVERCOMES[el] === element) || '';
5471
+ /** 月支本气所属五行 */
5472
+ const mainElOf = (branch) => elOf((HIDDEN[branch] || [])[0] || '');
5473
+
5474
+ /**
5475
+ * 判四柱天干的五合化与不化。
5476
+ * @param {object} pillars 四柱(bazi.js 的 pillar 对象;用到 stem 与 branch)
5477
+ * @param {string} monthBranch 月支(省略时取 pillars.month.branch)
5478
+ * @param {string} dayStem 日干(省略时取 pillars.day.stem)
5479
+ * @param {string[]} keys 参与判定的柱;时辰未知时传 ['year','month','day']
5480
+ */
5481
+ function judgeHehua(pillars, monthBranch, dayStem, keys = KEYS) {
5482
+ const slots = (Array.isArray(keys) ? keys : KEYS)
5483
+ .filter((k) => pillars && pillars[k] && pillars[k].stem && pillars[k].branch)
5484
+ .map((k) => ({ key: k, label: LABEL[k] || k, stem: pillars[k].stem, branch: pillars[k].branch }));
5485
+ const mb = monthBranch || (pillars && pillars.month && pillars.month.branch) || '';
5486
+ const ds = dayStem || (pillars && pillars.day && pillars.day.stem) || '';
5487
+
5488
+ const notes = [
5489
+ '反化(甲己化木、乙庚化木、丙辛化火或金、丁壬化火或水、戊癸化土或水)是近代易人的演绎,诸家分歧大,本插件不做。',
5490
+ '日元参与合化时,即使化成功仍以原五行论:问真说「五行的本质属性不会转变,只不过表现形式可能会发生变化」。',
5491
+ '天干五合未必以日元为主——年月干合化成功同样算数(问真所举己酉造就是年月干合)。',
5492
+ ];
5493
+
5494
+ if (slots.length < 2) {
5495
+ return {
5496
+ items: [], transformed: [], text: '天干不足两柱,五合无从判起。', method: METHOD, boundary: BOUNDARY, notes,
5497
+ };
5498
+ }
5499
+
5500
+ const monthEl = BRANCH_ELEMENT[mb] || '';
5501
+ const monthMain = mainElOf(mb);
5502
+ const items = [];
5503
+
5504
+ for (let i = 0; i < slots.length; i++) {
5505
+ for (let j = i + 1; j < slots.length; j++) {
5506
+ const a = slots[i];
5507
+ const b = slots[j];
5508
+ if (a.stem === b.stem) continue;
5509
+ const hua = heOf(a.stem, b.stem);
5510
+ if (!hua) continue;
5511
+
5512
+ const gap = j - i - 1;
5513
+ const closeness = gap === 0 ? '紧挨' : gap === 1 ? '隔合' : '遥合';
5514
+ const yin = isYangStem(a.stem) ? b : a;
5515
+ const yang = isYangStem(a.stem) ? a : b;
5516
+ const others = slots.filter((s) => s !== a && s !== b);
5517
+
5518
+ // 争合 / 妒合:第三干与这一对里的某一干另成五合
5519
+ let conflict = null;
5520
+ let conflictStem = '';
5521
+ for (const s of others) {
5522
+ if (!heOf(s.stem, a.stem) && !heOf(s.stem, b.stem)) continue;
5523
+ conflict = isYangStem(s.stem) ? '争合' : '妒合';
5524
+ conflictStem = s.stem;
5525
+ break;
5526
+ }
5527
+
5528
+ // ② 被化天干(阴干一侧)无同类帮扶。
5529
+ // 只算「同类(比劫)」,不算印:问真的唯一完整例「己酉 甲戌 壬戌 丁未」里,
5530
+ // 被化的己土有丁火为印(火生土)却仍判化成功——把印计进生扶会与它自己的例子冲突。
5531
+ const sameKind = others.filter((s) => elOf(s.stem) === elOf(yin.stem));
5532
+
5533
+ // ④ 引化物不被克:问真原文点明「月干/日干透出」与「月支本气」两处。
5534
+ const keEl = keOf(hua);
5535
+ const keMajor = others.filter((s) => elOf(s.stem) === keEl && (s.key === 'month' || s.key === 'day'));
5536
+ const keMinor = others.filter((s) => elOf(s.stem) === keEl && s.key !== 'month' && s.key !== 'day');
5537
+ const keMonth = !!keEl && monthMain === keEl;
5538
+
5539
+ const conditions = {
5540
+ adjacent: gap === 0,
5541
+ noConflict: !conflict,
5542
+ unrescued: sameKind.length === 0,
5543
+ monthLead: (monthEl && monthEl === hua) || (monthMain && monthMain === hua) || false,
5544
+ leadUnchecked: keMajor.length === 0 && !keMonth,
5545
+ };
5546
+ const ok = conditions.adjacent && conditions.noConflict && conditions.unrescued
5547
+ && conditions.monthLead && conditions.leadUnchecked;
5548
+
5549
+ const missing = [];
5550
+ if (!conditions.adjacent) missing.push(closeness === '隔合' ? '相隔一位(隔合)' : '相隔两位(遥合)');
5551
+ if (!conditions.noConflict) {
5552
+ missing.push(`${conflict}(另有${conflictStem}与${conflict === '争合' ? '同一阴干' : '同一阳干'}成合)`);
5553
+ }
5554
+ if (!conditions.unrescued) missing.push(`被化干${yin.stem}在天干有同类${sameKind.map((s) => s.stem).join('、')}帮扶`);
5555
+ if (!conditions.monthLead) missing.push(`月令${mb}(${monthEl || '—'})不是化神${hua}`);
5556
+ if (!conditions.leadUnchecked) {
5557
+ const who = [
5558
+ ...keMajor.map((s) => `${s.stem}(${s.label}干)`),
5559
+ keMonth ? `月支${mb}本气${keEl}` : '',
5560
+ ].filter(Boolean);
5561
+ missing.push(`引化物${hua}被${keEl}克:${who.join('、')}`);
5562
+ }
5563
+
5564
+ const status = ok ? '化成功'
5565
+ : !conditions.adjacent ? `${closeness}不化`
5566
+ : !conditions.noConflict ? `${conflict}不化`
5567
+ : '合绊不化';
5568
+
5569
+ const pair = `${a.stem}${b.stem}`;
5570
+ const positionText = `${a.label}干${a.stem}与${b.label}干${b.stem}`;
5571
+ const leadText = monthEl === monthMain || !monthMain
5572
+ ? `月令${mb}为${monthEl}`
5573
+ : `月令${mb}为${monthEl}、本气${monthMain}`;
5574
+ const evidence = ok
5575
+ ? `${positionText}紧挨,成${pair}合化${hua};${leadText},正好引化;`
5576
+ + `被化干${yin.stem}${elOf(yin.stem)}在天干无同类帮扶;克${hua}的${keEl}不在月干与日干,月支本气也不是它。`
5577
+ : `${positionText}成${pair}合,但${missing.join(';')},只作合绊,不论化。`;
5578
+
5579
+ items.push({
5580
+ pair,
5581
+ huaElement: hua,
5582
+ positions: `${a.key}-${b.key}`,
5583
+ positionText,
5584
+ closeness,
5585
+ distance: gap,
5586
+ yinStem: yin.stem,
5587
+ yangStem: yang.stem,
5588
+ conflict,
5589
+ conflictStem: conflictStem || null,
5590
+ conditions,
5591
+ status,
5592
+ ok,
5593
+ dayMasterInvolved: !!ds && (a.stem === ds || b.stem === ds),
5594
+ evidence,
5595
+ });
5596
+ }
5597
+ }
5598
+
5599
+ const transformed = items.filter((x) => x.ok).map((x) => `${x.pair}化${x.huaElement}`);
5600
+ const lines = items.map((x) => `【${x.status}】${x.evidence}`);
5601
+ if (items.some((x) => x.ok && x.dayMasterInvolved)) {
5602
+ lines.push('日元参与的那一组即使化成功,五行属性仍按原干论,只表现形式变。');
5603
+ }
5604
+ // 克化神之五行只在年干/时干出现时不挡化,但要写明——离得远,力道打折
5605
+ for (const x of items) {
5606
+ if (!x.ok) continue;
5607
+ const keEl = keOf(x.huaElement);
5608
+ const far = slots.filter((s) => elOf(s.stem) === keEl && x.positions.split('-').indexOf(s.key) < 0
5609
+ && s.key !== 'month' && s.key !== 'day');
5610
+ if (far.length) lines.push(`${x.pair}化${x.huaElement}:克化神的${keEl}只在${far.map((s) => `${s.label}干`).join('、')},被化神隔开,不挡化。`);
5611
+ }
5612
+ const text = items.length ? lines.join('\n') : '四柱天干未见五合。';
5613
+
5614
+ return { items, transformed, text, method: METHOD, boundary: BOUNDARY, notes };
5615
+ }
5616
+
5617
+ return { judgeHehua };
5618
+ })();
5619
+
5242
5620
  __mods.geju = (function () {
5243
5621
  // 八字格局、用神与行运评分
5244
5622
  //
@@ -6091,6 +6469,198 @@ function scoreLuck(ganzhi, frame) {
6091
6469
  return { ganzhi, score: total, tier, stemTenGod: godStem, reasons, note: `${godStem}运,${tier}(${total})` };
6092
6470
  }
6093
6471
 
6472
+ // ── 财库 ────────────────────────────────────────────────────
6473
+
6474
+ // 五行之墓:木墓未、火墓戌、金墓丑、水墓辰;土取戊土十二长生的墓位(戌)。
6475
+ // 这样取,问真《专业知识·八字断财富技法》那张表五格全部对得上:
6476
+ // 木日主财土 → 土墓戌;水日主财火 → 火墓戌;火日主财金 → 金墓丑;
6477
+ // 土日主财水 → 水墓辰;金日主财木 → 木墓未。
6478
+ // 若改用「水土同宫」把土墓放辰,只有木日主一格会落到辰,与问真表冲突,故取戌。
6479
+ const TOMB_OF = { 木: '未', 火: '戌', 土: '戌', 金: '丑', 水: '辰' };
6480
+ const BRANCH_CHONG = {
6481
+ 子: '午', 午: '子', 丑: '未', 未: '丑', 寅: '申', 申: '寅',
6482
+ 卯: '酉', 酉: '卯', 辰: '戌', 戌: '辰', 巳: '亥', 亥: '巳',
6483
+ };
6484
+ const CAIKU_WEAK_PCT = 8;
6485
+
6486
+ /**
6487
+ * 财库:日主所克五行(财)的墓库,落在四支上;库被冲开才是「开库」。
6488
+ * @param {object} p
6489
+ * @param {string} p.dayStem 日干
6490
+ * @param {object} p.pillars 四柱
6491
+ * @param {object} p.wuxing 五行分值
6492
+ * @param {object} p.yongshen 喜忌结果
6493
+ */
6494
+ function caiKuOf({ dayStem, pillars = {}, wuxing = {}, yongshen = {} }) {
6495
+ const roles = elementRoles(dayStem);
6496
+ const caiEl = roles.cai;
6497
+ const store = TOMB_OF[caiEl] || '';
6498
+ const keys = ['year', 'month', 'day', 'hour'].filter((k) => pillars[k] && pillars[k].branch);
6499
+ const at = keys.filter((k) => pillars[k].branch === store);
6500
+ const openerBranch = BRANCH_CHONG[store] || '';
6501
+ const openers = keys.filter((k) => pillars[k].branch === openerBranch);
6502
+
6503
+ const total = Object.values(wuxing).reduce((n, v) => n + (Number(v) || 0), 0);
6504
+ const w = (el) => Math.round((Number(wuxing[el]) || 0) * 10) / 10;
6505
+ const pctOf = (el) => (total > 0 ? Math.round((w(el) / total) * 1000) / 10 : 0);
6506
+ const caiPct = pctOf(caiEl);
6507
+ const caiWeak = caiPct < CAIKU_WEAK_PCT;
6508
+
6509
+ const favor = Array.isArray(yongshen.favor) ? yongshen.favor : [];
6510
+ const avoid = Array.isArray(yongshen.avoid) ? yongshen.avoid : [];
6511
+ const favorable = favor.includes(caiEl);
6512
+ const avoidable = avoid.includes(caiEl);
6513
+ const opened = at.length > 0 && openers.length > 0;
6514
+ // 财星入库:库支的藏干里出现财这一行(不论本气/中气/余气),与「财库」是两件事。
6515
+ // 没有库支时这两项一律为假——不能拿「本该是库的那一支」的藏干去充数。
6516
+ const hiddenEls = at.length ? (HIDDEN[store] || []).map((h) => STEM_ELEMENT[h]) : [];
6517
+ const caiInStore = hiddenEls.includes(caiEl);
6518
+ const mainInStore = at.length > 0 && (HIDDEN[store] || []).slice(0, 1).map((h) => STEM_ELEMENT[h]).includes(caiEl);
6519
+
6520
+ const label = (ks) => ks.map((k) => ({ year: '年', month: '月', day: '日', hour: '时' }[k])).join('、');
6521
+
6522
+ let verdict = '无财库';
6523
+ let detail = `日主${dayStem}${roles.me},财为${caiEl},${caiEl}之墓在${store};四支里没有${store},本盘不立财库`
6524
+ + `${openers.length ? `(${label(openers)}支见${openerBranch},但没有${store}可冲,冲不成库)` : ''}。`;
6525
+ if (at.length) {
6526
+ // 四库每一支都含所墓那一行的余气(戌藏丁、丑藏辛、辰藏癸、未藏乙),
6527
+ // 所以「库里有财」几乎恒真;真正要分的是本气与余气——这才是「财星入库」的深浅。
6528
+ const storeNote = mainInStore
6529
+ ? `(${store}藏干本气即${caiEl},正合「财星入库」)`
6530
+ : `(${store}藏干里的${caiEl}只是余气,财星算入了库,但入得浅)`;
6531
+ const head = `日主${dayStem}${roles.me},财为${caiEl},${caiEl}之墓在${store};`
6532
+ + `本盘${label(at)}支见${store},财库成立${caiInStore ? storeNote : ',库中不见财星'}。`;
6533
+ const tail = openers.length
6534
+ ? `${label(openers)}支见${openerBranch},${store}${openerBranch}相冲,库门被冲开。`
6535
+ : `四支里没有${openerBranch}来冲,库是闭的——要等岁运引动。`;
6536
+ const step = (() => {
6537
+ if (favorable && !caiWeak) return opened ? `财${caiEl}为喜用且不弱(${caiPct}%),库开则财有出路,主发。` : `财${caiEl}为喜用且不弱(${caiPct}%),但库未开,是「有财待发」,不是已经发财。`;
6538
+ if (favorable && caiWeak) return opened ? `财${caiEl}为喜用但偏弱(${caiPct}%),库开只是流动起来,发而不厚,先补财再谈库。` : `财${caiEl}为喜用但偏弱(${caiPct}%),库又未开,宜先扶财。`;
6539
+ if (avoidable) return opened ? `财${caiEl}为忌(${caiPct}%),开库反主破财,冲得越实越明显。` : `财${caiEl}为忌(${caiPct}%),但库未开,破财之势未启。`;
6540
+ return opened ? `财${caiEl}在喜忌里为中性(${caiPct}%),开库只算动了财,吉凶看岁运把哪一边引起来。` : `财${caiEl}在喜忌里为中性(${caiPct}%),库未开,暂不作财库论。`;
6541
+ })();
6542
+ verdict = opened
6543
+ ? (favorable && !caiWeak ? '开库主发' : avoidable ? '开库反主破财' : favorable ? '开库发而不厚' : '开库,吉凶待引动')
6544
+ : (favorable ? (caiWeak ? '库闭财弱' : '库闭待冲开') : avoidable ? '库闭未开' : '库闭,吉凶待引动');
6545
+ detail = `${head}${tail}${step}`;
6546
+ }
6547
+
6548
+ return {
6549
+ dayElement: roles.me,
6550
+ caiElement: caiEl,
6551
+ store,
6552
+ present: at.length > 0,
6553
+ positions: at,
6554
+ opener: openerBranch,
6555
+ opened,
6556
+ openerPositions: openers,
6557
+ caiInStore,
6558
+ mainInStore,
6559
+ caiPct,
6560
+ caiWeak,
6561
+ favorState: favorable ? '喜' : avoidable ? '忌' : '中',
6562
+ verdict,
6563
+ detail,
6564
+ rule: '财库=财星(日主所克那一行)之墓在四支上;开库=库支被对冲。「开库才发」有两个前提:财为喜用、且财不弱;财为忌时开库反主破财。',
6565
+ method: `五行之墓取木未/火戌/金丑/水辰,土取戊土长生墓位戌;问真原表作「水木日主在戌、火在丑、土在辰、金在未」,与本法五格全同。财「不弱」以全局占比 >= ${CAIKU_WEAK_PCT}% 折算,是本插件口径,非古法原数。`,
6566
+ boundary: '只作只读标注:不改旺衰分、不改喜忌、不参与取格。另一说把辰当作「水土同宫」的土墓,则木日主财库会落在辰,本插件不取此说。',
6567
+ };
6568
+ }
6569
+
6570
+ // ── 三平衡(富贵层次的解读方向)────────────────────────────
6571
+
6572
+ // 地支阴阳:论八字时以藏干本气的阴阳定,不以奇偶定(问真《基础知识·干支上》)。
6573
+ // 子藏癸、午藏丁、卯藏乙、酉藏辛 → 阴;亥藏壬、巳藏丙、寅藏甲、申藏庚 → 阳。
6574
+ const BRANCH_YINYANG = {
6575
+ 子: '阴', 丑: '阴', 寅: '阳', 卯: '阴', 辰: '阳', 巳: '阳',
6576
+ 午: '阴', 未: '阴', 申: '阳', 酉: '阴', 戌: '阳', 亥: '阳',
6577
+ };
6578
+ const BALANCE_SPREAD_MAX = 22;
6579
+ const BALANCE_MIN_PCT = 4;
6580
+ const BALANCE_YINYANG_LO = 3;
6581
+ const BALANCE_YINYANG_HI = 5;
6582
+ const BALANCE_CLIMATE_W = 0.3;
6583
+
6584
+ /**
6585
+ * 三平衡:五行平衡 / 阴阳平衡 / 寒暖燥湿平衡。
6586
+ * @param {object} p
6587
+ * @param {string} p.dayStem 日干
6588
+ * @param {object} p.pillars 四柱
6589
+ * @param {object} p.wuxing 五行分值
6590
+ * @param {object} p.climate judgeClimate 的结果(yongshen.climate)
6591
+ * @param {object} p.strength 旺衰结果(只用于文案)
6592
+ */
6593
+ function balanceOf({ dayStem, pillars = {}, wuxing = {}, climate = null, strength = null }) {
6594
+ const total = Object.values(wuxing).reduce((n, v) => n + (Number(v) || 0), 0);
6595
+ const w = (el) => Math.round((Number(wuxing[el]) || 0) * 10) / 10;
6596
+ const pctOf = (el) => (total > 0 ? Math.round((w(el) / total) * 1000) / 10 : 0);
6597
+
6598
+ // ① 五行平衡:最高与最低的占比差,加上「有没有几乎缺掉的
6599
+ const pcts = ELEMENTS.map((el) => ({ element: el, pct: pctOf(el) }));
6600
+ const spread = Math.round((Math.max(...pcts.map((x) => x.pct)) - Math.min(...pcts.map((x) => x.pct))) * 10) / 10;
6601
+ const lowest = pcts.slice().sort((a, b) => a.pct - b.pct)[0];
6602
+ const highest = pcts.slice().sort((a, b) => b.pct - a.pct)[0];
6603
+ const wuxingOk = spread <= BALANCE_SPREAD_MAX && lowest.pct >= BALANCE_MIN_PCT;
6604
+ const wuxingDetail = wuxingOk
6605
+ ? `五行占比在 ${lowest.pct}%–${highest.pct}% 之间,极差 ${spread} 个百分点,没有明显缺项。`
6606
+ : lowest.pct < BALANCE_MIN_PCT
6607
+ ? `${lowest.element}只有 ${lowest.pct}%,近乎缺项;${highest.element}高到 ${highest.pct}%,偏得明显。`
6608
+ : `${highest.element}高到 ${highest.pct}%、${lowest.element}只有 ${lowest.pct}%,极差 ${spread} 个百分点,偏枯。`;
6609
+
6610
+ // ② 阴阳平衡:天干按奇偶,地支按藏干本气
6611
+ const stemKeys = ['year', 'month', 'day', 'hour'].filter((k) => pillars[k] && pillars[k].stem);
6612
+ const yStem = stemKeys.filter((k) => isYangStem(pillars[k].stem)).length;
6613
+ const yBranch = stemKeys.filter((k) => BRANCH_YINYANG[pillars[k].branch] === '阳').length;
6614
+ const yang = yStem + yBranch;
6615
+ const yin = stemKeys.length * 2 - yang;
6616
+ const yinyangOk = yang >= BALANCE_YINYANG_LO && yang <= BALANCE_YINYANG_HI;
6617
+ const pure = yang === 0 ? '纯阴' : yang === stemKeys.length * 2 ? '纯阳' : '';
6618
+ const yinyangDetail = pure
6619
+ ? `${pure}之局(阳 ${yang}/阴 ${yin}),课里说纯阴纯阳减贵减富。`
6620
+ : yinyangOk
6621
+ ? `天干阳 ${yStem}、地支阳 ${yBranch},合计阳 ${yang}/阴 ${yin},阴阳相配。`
6622
+ : `天干阳 ${yStem}、地支阳 ${yBranch},合计阳 ${yang}/阴 ${yin},一边倒。`;
6623
+
6624
+ // ③ 寒暖燥湿:气候平和,或调候之物在原局有根
6625
+ const kind = climate && climate.kind ? climate.kind : '';
6626
+ const needEl = climate && climate.need && climate.need.element ? climate.need.element : '';
6627
+ const needW = needEl ? w(needEl) : 0;
6628
+ const climateOk = kind === '平和' || (!!needEl && needW >= BALANCE_CLIMATE_W);
6629
+ const climateDetail = !kind
6630
+ ? '未见气候判定,本项不计。'
6631
+ : kind === '平和'
6632
+ ? `气候平和(${kind}),寒暖燥湿不偏。`
6633
+ : needEl
6634
+ ? climateOk
6635
+ ? `气候偏${kind},需${needEl}调候;原局${needEl}已有 ${needW} 分,调候之物在位。`
6636
+ : `气候偏${kind},需${needEl}调候;原局${needEl}只有 ${needW} 分,调候之物不实。`
6637
+ : `气候偏${kind},但未见明确调候之物。`;
6638
+
6639
+ const hits = [wuxingOk, yinyangOk, climateOk].filter(Boolean).length;
6640
+ const tier = hits === 3 ? '三备' : hits === 2 ? '两备' : hits === 1 ? '一备' : '零备';
6641
+ const tierText = {
6642
+ 三备: '三方面平衡全备,课里按大富大贵论方向。',
6643
+ 两备: '三方面备了两项,课里按中富中贵论方向。',
6644
+ 一备: '三方面只备一项,课里按小富小贵论方向。',
6645
+ 零备: '三项都不备,课里不给富贵层次;这不等于命薄,只说明这套衡量法在这一盘上不适用。',
6646
+ }[tier];
6647
+
6648
+ return {
6649
+ wuxing: { ok: wuxingOk, spread, highest: highest.element, lowest: lowest.element, pcts, detail: wuxingDetail },
6650
+ yinyang: { ok: yinyangOk, yang, yin, yangStems: yStem, yangBranches: yBranch, pure, detail: yinyangDetail },
6651
+ climate: { ok: climateOk, kind, need: needEl || null, needWeight: needW, detail: climateDetail },
6652
+ hits,
6653
+ tier,
6654
+ text: `五行平衡:${wuxingOk ? '备' : '不备'}——${wuxingDetail}阴阳平衡:${yinyangOk ? '备' : '不备'}——${yinyangDetail}寒暖燥湿:${climateOk ? '备' : '不备'}——${climateDetail}${tierText}`,
6655
+ strengthNote: strength && strength.level ? `日主${dayStem},旺衰为${strength.level}。` : '',
6656
+ rule: '问真《专业知识·论八字富贵层次》:五行平衡、阴阳平衡、寒暖燥湿平衡,三方面全备为大富大贵,两备为中富中贵,一备为小富小贵。',
6657
+ method: `阈值是本插件的折算口径,不是古法原数:五行看最高最低占比差 <= ${BALANCE_SPREAD_MAX} 个百分点且无一项低于 ${BALANCE_MIN_PCT}%;`
6658
+ + `阴阳看八位(四天干奇偶 + 四地支本气)阳数在 ${BALANCE_YINYANG_LO}–${BALANCE_YINYANG_HI} 之间;`
6659
+ + `寒暖燥湿看气候为平和,或调候之物在原局有 ${BALANCE_CLIMATE_W} 分以上。`,
6660
+ boundary: '只作解读方向:不改旺衰分、不改喜忌、不参与取格。格局法的贵贱十式另有专章,不并入这三项。',
6661
+ };
6662
+ }
6663
+
6094
6664
  // ── 对外入口 ────────────────────────────────────────────────
6095
6665
 
6096
6666
  /**
@@ -6117,6 +6687,12 @@ function analyzeBaziFrame({ pillars, dayStem, monthBranch, strength, wuxing }) {
6117
6687
  const bingyao = bingyaoOf({ dayStem, strength, wuxing, yongshen, geju });
6118
6688
  // 闲神:只读标注
6119
6689
  const xianshen = xianshenOf({ dayStem, wuxing, pillars, yongshen });
6690
+ // 财库:只读标注,复用上面的喜忌
6691
+ const caiKu = caiKuOf({ dayStem, pillars, wuxing, yongshen });
6692
+ // 三平衡:只读标注,气候取用神层已判好的那一个
6693
+ const balance = balanceOf({
6694
+ dayStem, pillars, wuxing, climate: yongshen.climate || null, strength,
6695
+ });
6120
6696
  return {
6121
6697
  geju,
6122
6698
  primary: month,
@@ -6125,6 +6701,8 @@ function analyzeBaziFrame({ pillars, dayStem, monthBranch, strength, wuxing }) {
6125
6701
  yongshen,
6126
6702
  bingyao,
6127
6703
  xianshen,
6704
+ caiKu,
6705
+ balance,
6128
6706
  patternScore,
6129
6707
  dayStem,
6130
6708
  monthBranch,
@@ -6133,7 +6711,7 @@ function analyzeBaziFrame({ pillars, dayStem, monthBranch, strength, wuxing }) {
6133
6711
  };
6134
6712
  }
6135
6713
 
6136
- return { tenGod, elementRoles, patternScoreOf, tongguanOf, bingyaoOf, xianshenOf, scoreLuck, analyzeBaziFrame };
6714
+ return { tenGod, elementRoles, patternScoreOf, tongguanOf, bingyaoOf, xianshenOf, scoreLuck, caiKuOf, balanceOf, analyzeBaziFrame };
6137
6715
  })();
6138
6716
 
6139
6717
  __mods.bazi = (function () {
@@ -6147,6 +6725,7 @@ const { bool } = (__mods.bool || {});
6147
6725
  const { nayinOf } = (__mods.nayin || {});
6148
6726
  const { SANHE } = (__mods.sanhe || {});
6149
6727
  const { analyzeBaziFrame, scoreLuck } = (__mods.geju || {});
6728
+ const { judgeHehua } = (__mods.hehua || {});
6150
6729
  const { branchStructureOf, weightPctOf } = (__mods.structure || {});
6151
6730
 
6152
6731
  // 地支藏干(本气 / 中气 / 余气)
@@ -6400,6 +6979,8 @@ function buildRelations(pillars, keys = ['year', 'month', 'day', 'hour']) {
6400
6979
  branches: uniq(branchOut),
6401
6980
  anhe: anheOf(pillars, keys),
6402
6981
  anheNote: '暗合只作取象与风水参考,不参与旺衰与格局;只出现一对时按课里可忽略',
6982
+ // 五合化与不化:另起一层判四条件,上面的 stems 文案保持不变(那里只说「待定」)
6983
+ hehua: judgeHehua(pillars, pillars.month ? pillars.month.branch : '', pillars.day ? pillars.day.stem : '', keys),
6403
6984
  };
6404
6985
  }
6405
6986
 
@@ -6677,7 +7258,15 @@ function buildBazi(input) {
6677
7258
  const monthBranch = pillars.month.branch;
6678
7259
 
6679
7260
  // 神煞:表驱动、双查法(年干/日干、年支/日支、月支、日柱、时柱),详见 engine/shensha.js
6680
- const shensha = computeBaziShensha(pillars, kongwang);
7261
+ // gender 供勾绞煞/元辰辨阴阳男女;年柱纳音五行供学堂/词馆
7262
+ const shensha = computeBaziShensha(pillars, kongwang, {
7263
+ gender,
7264
+ // nayin() 返回的是纳音名(字符串),不是对象——取五行须走 nayinOf()。
7265
+ // 这里长期写成 nayin(yearIdx).element 恒为 undefined,导致学堂/词馆(纳音长生/临官)
7266
+ // 与童子煞纳音法在真实排盘里从未命中过;单测因为直接喂了 yearNayinElement 而没暴露。
7267
+ yearNayinElement: nayinOf(yearIdx).element,
7268
+ yearKongwang: xunKongOf(pillars.year.ganzhi),
7269
+ });
6681
7270
 
6682
7271
  for (const key of ['year', 'month', 'day', 'hour']) {
6683
7272
  const pl = pillars[key];
@@ -7016,6 +7605,32 @@ function buildBazi(input) {
7016
7605
  out.strength.weightPct.placeholderHour = true;
7017
7606
  out.strength.weightPct.note = '时柱暂缺:时柱权重不计入合计(本盘 81%),不重新归一化;补上出生时刻后再按 100% 看';
7018
7607
  }
7608
+ // 财库与三平衡都用到了时支:财库看四支有没有库、有没有冲开,三平衡数地支阴阳。
7609
+ // 与结构同一条规矩——照实标占位,不把编出来的时支说成实有。
7610
+ if (out.frame && out.frame.caiKu) {
7611
+ const ck = out.frame.caiKu;
7612
+ ck.placeholderHour = true;
7613
+ // 判「这一条要不要紧」不能看占位时支碰巧有没有库/冲,要看结论本身是否依赖未知的时支:
7614
+ // 库与冲都已落在年月日三支上才稳;库没找到、或库找到了但冲没找到,
7615
+ // 都可能是因为真正的时支里正好有那一支,结论必须存疑。
7616
+ const atHour = (ck.positions || []).includes('hour') || (ck.openerPositions || []).includes('hour');
7617
+ const robust = ck.present && ck.opened && !atHour;
7618
+ ck.note = robust
7619
+ ? '时柱暂缺:库与冲都已落在年月日三支上,结论不受时支影响'
7620
+ : '时柱暂缺:库或开库可能落在未知的时支上,这一条只按正午占位算,补上出生时刻后可能整条改变';
7621
+ ck.detail = `${ck.detail}(时支为占位值)`;
7622
+ }
7623
+ if (out.frame && out.frame.balance) {
7624
+ const bal = out.frame.balance;
7625
+ bal.placeholderHour = true;
7626
+ bal.note = '时柱暂缺:阴阳的八位与五行占比都按正午时柱占位算过,补上出生时刻后层次可能变化';
7627
+ bal.text = `${bal.text}(阴阳与五行未含真实时柱,层次只作方向)`;
7628
+ }
7629
+ if (out.relations && out.relations.hehua) {
7630
+ const hh = out.relations.hehua;
7631
+ hh.placeholderHour = true;
7632
+ hh.text = `${hh.text}\n(时柱暂缺:只判了年月日三干,日干与时干那一组无从判起)`;
7633
+ }
7019
7634
  out.notes = [
7020
7635
  '时柱暂缺:未提供出生时刻,时柱不对外给出,也不计入神煞与干支关系',
7021
7636
  '旺衰、格局、用神、调候暂以正午时柱估算,补上出生时刻后可能改变',
@@ -22839,6 +23454,29 @@ function baziInterpret(r) {
22839
23454
  + `边界:暗合与上面的「地支关系」(三合、三会、六合、六冲、刑、害)是两条线,本插件不把它们合并计分;`
22840
23455
  + `${r.relations.anhe.length === 1 ? '本盘只出现一对,按课里口径可以直接忽略。' : `本盘共 ${r.relations.anhe.length} 对,可作取象参考,但仍不折旺衰。`}`,
22841
23456
  }] : []),
23457
+ // 五合化与不化:上面「天干关系」只写「化某待定」,这一节才拿四条件去判。
23458
+ // 判完仍然不改旺衰与喜忌——所以把「不改什么」写进节里,别让人当成合化后重排。
23459
+ ...(r.relations && r.relations.hehua && Array.isArray(r.relations.hehua.items) && r.relations.hehua.items.length ? [{
23460
+ key: 'hehua', label: '合化',
23461
+ text: `${r.relations.hehua.text}\n`
23462
+ + `口径:${r.relations.hehua.method}\n`
23463
+ + `边界:${r.relations.hehua.boundary}\n`
23464
+ + (r.relations.hehua.notes || []).map((n) => `· ${n}`).join('\n'),
23465
+ }] : []),
23466
+ // 财库:库在四支、冲开与否、财是喜是忌——三件事一起才有结论
23467
+ ...(frame.caiKu ? [{
23468
+ key: 'caiku', label: '财库',
23469
+ text: `【${frame.caiKu.verdict}】${frame.caiKu.detail}\n`
23470
+ + `口径:${frame.caiKu.rule}${frame.caiKu.method}\n`
23471
+ + `边界:${frame.caiKu.boundary}`,
23472
+ }] : []),
23473
+ // 三平衡:只给富贵层次的「解读方向」,不反改旺衰与喜忌
23474
+ ...(frame.balance ? [{
23475
+ key: 'balance', label: '三平衡',
23476
+ text: `【${frame.balance.tier}】${frame.balance.text}\n`
23477
+ + `口径:${frame.balance.rule}${frame.balance.method}\n`
23478
+ + `边界:${frame.balance.boundary}`,
23479
+ }] : []),
22842
23480
  (() => {
22843
23481
  const ss = r.shensha;
22844
23482
  const cols = { year: '年', month: '月', day: '日', hour: '时' };
@@ -26852,9 +27490,20 @@ function baziSummary(r) {
26852
27490
  : cl.label === '燥热' ? '火土偏燥,像久旱的地,需要水和湿气来松一松'
26853
27491
  : '寒暖相对均衡,没有极端的偏枯';
26854
27492
  const needEl = (cl.need && cl.need.element) || favor[0] || '';
27493
+ // 财库:库在不在、开没开、财是喜是忌——把三件事压成一句人话,接在总纲末尾
27494
+ const ck = (r.frame && r.frame.caiKu) || null;
27495
+ const caiKuLine = (() => {
27496
+ if (!ck) return '';
27497
+ if (!ck.present) return '财这一路没有立库,赚多少看明面上的财星与行运,不靠「开库」这一说。';
27498
+ if (ck.opened && ck.verdict === '开库主发') return `财有库(${ck.store}),而且库门被${ck.opener}冲开了:钱是能进来的,关键在于你肯不肯把它存住。`;
27499
+ if (ck.opened && ck.verdict === '开库反主破财') return `财有库(${ck.store})也被冲开了,但这一行在你这盘上是忌:动得越多漏得越快,稳比冲重要。`;
27500
+ if (ck.opened) return `财有库(${ck.store}),库门也开了,但财本身不算厚:有得有失,别指望一次翻身。`;
27501
+ return `财有库(${ck.store}),门还关着:不是没有,是要等对的时间或对的选择把它引出来。`;
27502
+ })();
26855
27503
  const lead = `${dm.stem || ''}${dm.element || ''}日主,生在${season}${month.branch || ''}月:${climateWord}。`
26856
27504
  + `${needEl ? `最需要的是${needEl}${cl.need && cl.need.why ? `——${cl.need.why}` : ''}。` : ''}`
26857
- + `整体${r.strength ? r.strength.level : '中和'},不是极旺也不是极弱,所以${r.strength && r.strength.level === '身弱' ? '很多事要靠外部条件配合,硬扛不如借力' : '撑得住,关键是别把力气用在错的地方'}。`;
27505
+ + `整体${r.strength ? r.strength.level : '中和'},不是极旺也不是极弱,所以${r.strength && r.strength.level === '身弱' ? '很多事要靠外部条件配合,硬扛不如借力' : '撑得住,关键是别把力气用在错的地方'}。`
27506
+ + caiKuLine;
26858
27507
 
26859
27508
  // ── 底色:十神权重前两位 ──
26860
27509
  const top2 = topGods.slice(0, 2).map(([k]) => k);
@@ -26909,6 +27558,17 @@ function baziSummary(r) {
26909
27558
  if (avoid.length) advice.push(`少把自己放在${avoid.slice(0, 2).join('、')}过重的环境里——不是不能碰,是别长期待在那种氛围中。`);
26910
27559
  if (top2.includes('印')) advice.push('给「想」设个时限:一件事想超过十分钟还没结论,就先做一个最小动作,用行动换信息。');
26911
27560
  if (gejuNames.includes('伤官见官')) advice.push('把标准用在事情上,不要用在人身上;对人提要求之前,先说清你需要什么。');
27561
+ // 三平衡:只作「往哪个方向补」的一句话,不给富贵层次的下断语(层次见解析层的三平衡节)
27562
+ const bal = (r.frame && r.frame.balance) || null;
27563
+ if (bal) {
27564
+ const gaps = [];
27565
+ if (!bal.wuxing.ok) gaps.push(`五行偏在${bal.wuxing.highest}、缺在${bal.wuxing.lowest}`);
27566
+ if (!bal.yinyang.ok) gaps.push(bal.yinyang.pure ? `${bal.yinyang.pure}之局` : `阴阳一边倒(阳 ${bal.yinyang.yang}/阴 ${bal.yinyang.yin})`);
27567
+ if (!bal.climate.ok) gaps.push(`寒暖燥湿没调匀(${bal.climate.kind})`);
27568
+ advice.push(gaps.length
27569
+ ? `结构上${gaps.join('、')}:不必去「补命」,把这几处当作长期要照看的方向就行。`
27570
+ : '五行、阴阳、寒暖燥湿三方面都还匀:这种盘最忌讳的是为了「更好」而硬改节奏,稳住就是优势。');
27571
+ }
26912
27572
 
26913
27573
  return {
26914
27574
  system: 'bazi',
@@ -29467,7 +30127,7 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, parseDate
29467
30127
  })();
29468
30128
 
29469
30129
  window.Engine = __mods.index;
29470
- window.__MP_VER = "0.65.0";
30130
+ window.__MP_VER = "0.67.0";
29471
30131
  </script>
29472
30132
  <script>
29473
30133
  // 两个 UI 共用的表单规则:宿主面板(src/app.js)与独立页(src/web-ui.js)。