dsh-metaphysics 0.22.0 → 0.38.2

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/engine/ziwei.js CHANGED
@@ -518,20 +518,25 @@ export function buildZiwei(input) {
518
518
  shensha: '长生、博士随大限顺逆;将前、岁前恒顺行;天伤恒在交友、天使恒在疾厄',
519
519
  masters: '命主按命宫地支,身主按生年地支',
520
520
  liunian: '流年命宫取该年地支宫;三方四正为本宫与 +4/+8/+6;并给该年所属大限与小限',
521
+ flyComposite: '三方四正取本宫、对宫与两个三合宫共四宫,四宫宫干各化禄权科忌共 16 条,按落宫归堆标会聚(双忌会、禄忌同宫、三化会、自化);只描会照,不折吉凶',
521
522
  changqu: '昌曲落宫只由时支决定,故与丑未的关系(夹/三合/同宫/无关)是结构性结论;absorb 的「清/杂」是启发式标记,依据昌曲化忌与会煞,不是断语',
522
523
  },
523
524
  };
524
525
 
525
526
  chart.patterns = detectPatterns(chart);
526
527
  chart.daxianList = daxianList(chart);
528
+ chart.fly = flyStars(chart);
529
+ chart.flyChains = flyChains(chart, { from: '命宫' });
530
+ chart.flyComposite = flyComposite(chart, { from: '命宫' });
527
531
  enrichLiunian(chart);
528
532
  // 流月/流日/流时:默认按本机当前时刻,可用 asOf 指定(如 "2026-10-22T16:00")
529
533
  chart.flow = flowOf(chart, input.asOf);
530
534
  chart.patternSummary = {
531
535
  count: chart.patterns.length,
532
536
  good: chart.patterns.filter((p) => p.tone === 'good').map((p) => p.name),
537
+ neutral: chart.patterns.filter((p) => p.tone === 'neutral').map((p) => p.name),
533
538
  bad: chart.patterns.filter((p) => p.tone === 'bad').map((p) => p.name),
534
- note: '格局只描述结构,不作吉凶断语;同一命盘可并存吉格与忌格',
539
+ note: '格局只描述结构,不作吉凶断语;同一命盘可并存吉格、中性结构与忌格',
535
540
  };
536
541
  return chart;
537
542
  }
@@ -573,19 +578,18 @@ export function detectPatterns(chart) {
573
578
 
574
579
  const lu = starBranchOf(chart, '禄存');
575
580
  const ma = starBranchOf(chart, '天马');
576
- if (lu >= 0 && ma >= 0 && (lu === ma || fix(lu - ma) === 6)) add('禄马交驰', `禄存在${chart.ziwei && BRANCHES[lu]},天马在${BRANCHES[ma]}`);
581
+ if (lu >= 0 && ma >= 0 && (lu === ma || fix(lu - ma) === 6)) add('禄马交驰', `禄存在${BRANCHES[lu]},天马在${BRANCHES[ma]}`);
577
582
 
578
583
  const huo = starBranchOf(chart, '火星');
579
584
  const ling = starBranchOf(chart, '铃星');
580
585
  if (fix(soulIdx - 1) === huo && fix(soulIdx + 1) === ling) add('火铃夹命', '火星在命宫前一宫、铃星在后一宫夹命');
581
586
  if (fix(soulIdx - 1) === ling && fix(soulIdx + 1) === huo) add('火铃夹命', '铃星与火星夹命');
582
587
 
588
+ // 擎羊在禄存 +1、陀罗在禄存 -1,两星只能夹「禄存」那一宫;
589
+ // 所以「羊陀夹忌」实际就是化忌与禄存同宫,按左右两侧去找永远找不到。
583
590
  const ji = chart.palaces.find((p) => p.stars.some((s) => s.mutagen === '忌'));
584
- if (ji) {
585
- const jb = BRANCHES.indexOf(ji.branch);
586
- if (fix(jb - 1) === starBranchOf(chart, '擎羊') && fix(jb + 1) === starBranchOf(chart, '陀罗')) {
587
- add('羊陀夹忌', `化忌在${ji.branch},擎羊陀罗夹之`);
588
- }
591
+ if (ji && lu >= 0 && BRANCHES.indexOf(ji.branch) === lu) {
592
+ add('羊陀夹忌', `化忌与禄存在${ji.branch}同宫,擎羊陀罗夹之`);
589
593
  }
590
594
 
591
595
  // 铃昌陀武:四星会于命宫三方四正
@@ -603,10 +607,14 @@ export function detectPatterns(chart) {
603
607
  // ── 以下为扩展格局(条件都是星位判断,evidence 写明落在哪宫)──
604
608
  const inSoul = (name) => soul.stars.some((s) => s.name === name);
605
609
  const nearStar = (name) => near.has(name);
610
+ // 「夹」只要求两星分居命宫前后,不分左右——日月、左右、魁钺本来就没有固定左右;
611
+ // 旧写法只认一种顺序,昌曲夹命与羊陀夹命因此从未命中,日月/左右/魁钺也漏掉一半。
606
612
  const jia = (a, b) => {
607
613
  const ba = starBranchOf(chart, a);
608
614
  const bb = starBranchOf(chart, b);
609
- return ba >= 0 && bb >= 0 && fix(ba + 1) === soulIdx && fix(bb - 1) === soulIdx;
615
+ if (ba < 0 || bb < 0) return false;
616
+ return (fix(ba + 1) === soulIdx && fix(bb - 1) === soulIdx)
617
+ || (fix(bb + 1) === soulIdx && fix(ba - 1) === soulIdx);
610
618
  };
611
619
  const mutagensIn = (indices) => {
612
620
  const set = new Set();
@@ -640,7 +648,7 @@ export function detectPatterns(chart) {
640
648
  if (jia('左辅', '右弼')) add('左右夹命', '左辅、右弼夹命宫');
641
649
  if (jia('文昌', '文曲')) add('昌曲夹命', '文昌、文曲夹命宫');
642
650
  if (jia('天魁', '天钺')) add('魁钺夹命', '天魁、天钺夹命宫');
643
- if (jia('擎羊', '陀罗')) add('羊陀夹命', '擎羊、陀罗夹命宫');
651
+ if (jia('擎羊', '陀罗')) add('羊陀夹命', `禄存在${BRANCHES[soulIdx]}守命,擎羊陀罗前后夹之`);
644
652
 
645
653
  // 四化
646
654
  const muts = mutagensIn(sanfang);
@@ -655,9 +663,13 @@ export function detectPatterns(chart) {
655
663
  const lianzhen = starBranchOf(chart, '廉贞');
656
664
  const tianxiang = starBranchOf(chart, '天相');
657
665
  const qingyang = starBranchOf(chart, '擎羊');
658
- if (lianzhen >= 0 && qingyang >= 0 && tianxiang >= 0
659
- && fix(lianzhen + 1) === tianxiang && fix(qingyang - 1) === tianxiang) {
660
- add('刑囚夹印', '廉贞与擎羊夹天相(刑囚夹印)');
666
+ // 天相与廉贞永远隔偶数宫,字面上的「廉贞、擎羊夹天相」不可能成立;
667
+ // 通行说法取「廉贞天相同守命宫于子午、擎羊同宫」——判的是守命那一宫,其它宫位同宫不算。
668
+ // 命宫卯酉、廉贞天相对照遇擎羊的变体未纳入。
669
+ if (lianzhen >= 0 && tianxiang >= 0 && qingyang >= 0
670
+ && lianzhen === tianxiang && qingyang === tianxiang && tianxiang === soulIdx
671
+ && (tianxiang === 0 || tianxiang === 6)) {
672
+ add('刑囚夹印', `廉贞天相同守命宫${BRANCHES[tianxiang]},擎羊同宫`);
661
673
  }
662
674
  if (near.has('贪狼') && (near.has('火星') || near.has('铃星'))) {
663
675
  add('火贪铃贪', `贪狼与${near.has('火星') ? '火星' : '铃星'}会于命宫三方四正`);
@@ -674,7 +686,7 @@ export function detectPatterns(chart) {
674
686
  .map((p) => ({ ...p, tone: PATTERN_TONE[p.name] || 'neutral' }));
675
687
  }
676
688
 
677
- const PATTERN_TONE = {
689
+ export const PATTERN_TONE = {
678
690
  紫府同宫: 'good', 紫府朝垣: 'good', 君臣庆会: 'good', 极向离明: 'good',
679
691
  七杀朝斗: 'good', 英星入庙: 'good', 石中隐玉: 'good', 巨日同宫: 'good',
680
692
  日月夹命: 'good', 日月对照: 'good', 左右夹命: 'good', 昌曲夹命: 'good',
@@ -716,6 +728,179 @@ export function daxianList(chart) {
716
728
  .sort((a, b) => a.ages[0] - b.ages[0]);
717
729
  }
718
730
 
731
+ // ── 四化飞星:宫干四化飞向哪一宫,以及「串连」────────────────────
732
+ // 生年四化看「这颗星先天带着什么」,飞星四化看「这一宫自己会去找谁」:
733
+ // 宫干定出四个化星,星曜落在哪一宫,就是这一宫的禄/权/科/忌飞向哪里。
734
+ // 串连(忌转忌、科转科…)是同一支化一路跟下去:命宫化忌入 A 宫,A 宫的宫干再化忌入 B 宫……
735
+ // 走到回到已访问过的宫就成环(传统讲的「忌出」「自化」都在这一步显现)。
736
+
737
+ export const FLY_TYPES = ['禄', '权', '科', '忌'];
738
+
739
+ // 某天干下某一化的星曜;表里没有就返回 null(不会凭印象补)
740
+ export function flyStarOf(stem, type) {
741
+ const map = MUTAGEN[stem];
742
+ if (!map) return null;
743
+ for (const [star, t] of Object.entries(map)) if (t === type) return star;
744
+ return null;
745
+ }
746
+
747
+ // 12 宫各自的四化落点(一次算全,供面板与解读共用)
748
+ export function flyStars(chart) {
749
+ const palaces = chart.palaces || [];
750
+ return palaces.map((p) => ({
751
+ palace: p.palace,
752
+ branch: p.branch,
753
+ stem: p.stem,
754
+ flies: FLY_TYPES.map((type) => {
755
+ const star = flyStarOf(p.stem, type);
756
+ const b = star ? starBranchOf(chart, star) : -1;
757
+ const target = b >= 0 ? palaces.find((x) => x.branch === BRANCHES[b]) : null;
758
+ return {
759
+ type,
760
+ star,
761
+ to: target ? target.palace : null,
762
+ toBranch: target ? target.branch : null,
763
+ // 落回本宫即自化:这一宫自己化出去又回到自己
764
+ self: !!(target && target.palace === p.palace),
765
+ };
766
+ }),
767
+ }));
768
+ }
769
+
770
+ // 从某一宫出发,跟着同一支化逐跳;ended 说明为什么停:
771
+ // cycle=回到走过的宫(成环)、no-star=该干这一化无星、off-chart=星未上盘、max=走满上限
772
+ export function flyChain(chart, { from = '命宫', type = '忌', maxSteps = 12 } = {}) {
773
+ const palaces = chart.palaces || [];
774
+ const start = palaces.find((p) => p.palace === from) || palaces[0];
775
+ if (!start) return null;
776
+ const steps = [];
777
+ const seen = new Set([start.palace]);
778
+ let cur = start;
779
+ let ended = 'max';
780
+ for (let i = 0; i < Math.max(1, maxSteps); i++) {
781
+ const star = flyStarOf(cur.stem, type);
782
+ if (!star) { ended = 'no-star'; break; }
783
+ const b = starBranchOf(chart, star);
784
+ if (b < 0) { ended = 'off-chart'; break; }
785
+ const to = palaces.find((x) => x.branch === BRANCHES[b]);
786
+ steps.push({ from: cur.palace, fromBranch: cur.branch, fromStem: cur.stem, star, type, to: to.palace, toBranch: to.branch });
787
+ if (seen.has(to.palace)) { ended = 'cycle'; break; }
788
+ seen.add(to.palace);
789
+ cur = to;
790
+ }
791
+ return {
792
+ from: start.palace,
793
+ type,
794
+ steps,
795
+ path: [start.palace, ...steps.map((s) => s.to)],
796
+ ended,
797
+ closed: ended === 'cycle',
798
+ };
799
+ }
800
+
801
+ // 某一宫的四支化各串一条(默认命宫)
802
+ export function flyChains(chart, { from = '命宫', maxSteps = 12 } = {}) {
803
+ const out = {};
804
+ for (const type of FLY_TYPES) out[type] = flyChain(chart, { from, type, maxSteps });
805
+ return out;
806
+ }
807
+
808
+ // ── 三方四正复合飞化:四宫一起飞、看落到同一宫的会聚 ─────────────────
809
+ // 单宫飞化回答「这一宫自己去找谁」;三方四正看的是本宫连同对宫、两个三合宫
810
+ // 四股力同时飞出去,最后在哪一宫会到一起。会在一处的化越多,那一宫被牵动的力道越集中。
811
+ // 只归堆与标会照,不折吉凶:同样是双忌会一宫,落在生年忌和落在生年禄上意思完全不同。
812
+ const PALACE_SUFFIX = (p) => `${p}${String(p).endsWith('宫') ? '' : '宫'}`;
813
+
814
+ export function flyComposite(chart, { from = '命宫' } = {}) {
815
+ const palaces = chart.palaces || [];
816
+ const src = palaces.find((p) => p.palace === from) || palaces[0];
817
+ if (!src) return null;
818
+ const names = Array.isArray(src.sanfang) && src.sanfang.length
819
+ ? [...new Set(src.sanfang)].slice(0, 4)
820
+ : [src.palace];
821
+
822
+ const sources = [];
823
+ for (const name of names) {
824
+ const p = palaces.find((x) => x.palace === name);
825
+ if (!p) continue;
826
+ sources.push({
827
+ palace: p.palace,
828
+ branch: p.branch,
829
+ stem: p.stem,
830
+ flies: FLY_TYPES.map((type) => {
831
+ const star = flyStarOf(p.stem, type);
832
+ const b = star ? starBranchOf(chart, star) : -1;
833
+ const target = b >= 0 ? palaces.find((x) => x.branch === BRANCHES[b]) : null;
834
+ return {
835
+ type,
836
+ star,
837
+ to: target ? target.palace : null,
838
+ toBranch: target ? target.branch : null,
839
+ self: !!(target && target.palace === p.palace),
840
+ };
841
+ }),
842
+ });
843
+ }
844
+
845
+ // 16 条飞化按落宫归堆;未上盘的星不计入落点
846
+ const targets = [];
847
+ for (const p of palaces) {
848
+ const incoming = [];
849
+ for (const s of sources) {
850
+ for (const f of s.flies) {
851
+ if (f.to === p.palace) {
852
+ incoming.push({ from: s.palace, fromBranch: s.branch, fromStem: s.stem, type: f.type, star: f.star, self: f.self });
853
+ }
854
+ }
855
+ }
856
+ if (!incoming.length) continue;
857
+ targets.push({
858
+ palace: p.palace,
859
+ branch: p.branch,
860
+ incoming,
861
+ types: [...new Set(incoming.map((x) => x.type))],
862
+ count: incoming.length,
863
+ });
864
+ }
865
+ targets.sort((a, b) => b.count - a.count || BRANCHES.indexOf(a.branch) - BRANCHES.indexOf(b.branch));
866
+
867
+ const jiAt = (t) => t.incoming.filter((x) => x.type === '忌').length;
868
+ const groups = {
869
+ doubleJi: targets.filter((t) => jiAt(t) >= 2),
870
+ luJi: targets.filter((t) => t.types.includes('禄') && t.types.includes('忌')),
871
+ tripleHua: targets.filter((t) => t.types.length >= 3),
872
+ selfHua: targets.filter((t) => t.incoming.some((x) => x.self)),
873
+ };
874
+
875
+ const labels = [];
876
+ for (const t of groups.doubleJi) labels.push(`${['', '', '双忌', '三忌', '四忌'][jiAt(t)] || `${jiAt(t)}忌`}会${PALACE_SUFFIX(t.palace)}`);
877
+ for (const t of groups.luJi) labels.push(`禄忌同宫${PALACE_SUFFIX(t.palace)}`);
878
+ const HUA_NUM = { 3: '三化会', 4: '四化会' };
879
+ for (const t of groups.tripleHua) labels.push(`${HUA_NUM[t.types.length] || `${t.types.length}化会`}${PALACE_SUFFIX(t.palace)}`);
880
+ for (const t of groups.selfHua) labels.push(`${PALACE_SUFFIX(t.palace)}自化`);
881
+
882
+ const byType = {};
883
+ for (const type of FLY_TYPES) {
884
+ byType[type] = sources
885
+ .map((s) => {
886
+ const f = s.flies.find((x) => x.type === type);
887
+ return f && f.to ? { from: s.palace, star: f.star, to: f.to, self: f.self } : null;
888
+ })
889
+ .filter(Boolean);
890
+ }
891
+
892
+ return {
893
+ from: src.palace,
894
+ sanfang: sources.map((s) => s.palace),
895
+ sources,
896
+ targets,
897
+ groups,
898
+ byType,
899
+ labels,
900
+ note: '三方四正取本宫、对宫与两个三合宫共四宫,四宫宫干各化禄权科忌共 16 条飞化,按落宫归堆;只在落宫相同(会照)时标会聚,单条飞出不另立标签。只描会照与方向,不折吉凶,也未叠大限流年四化。',
901
+ };
902
+ }
903
+
719
904
  // ── 流年四化落宫 ────────────────────────────────────────────
720
905
 
721
906
  export function enrichLiunian(chart) {
package/index.js CHANGED
@@ -19,9 +19,9 @@ const TOOL_NAME = 'metaphysics_chart';
19
19
 
20
20
  const DESCRIPTION = [
21
21
  '排中国传统命理盘(玄学·命理·占卜,用户说「玄学」「算命」「占卜」时也用本工具)与塔罗:四柱八字(bazi)、紫微斗数(ziwei)、六爻纳甲(liuyao)、梅花易数(meihua)、大六壬(daliuren)、奇门遁甲(qimen)、合盘(hepan)或塔罗抽牌(tarot)。',
22
- '另有速查类:黄历(almanac,值日十二神/时辰吉凶/二十八宿/胎神/吉神方位/纳音/六合三合)、择日(zeri)、称骨(chenggu)、小六壬(xiaoliuren)、星座(star)、生命数字(numerology)、人生 K 线(trend)、风水(fengshui)、起名(name)、公农历互转(convert)。',
23
- '当用户明确要求“玄学 / 算命 / 占卜 / 排盘 / 算八字 / 看四柱 / 排紫微盘 / 起卦 / 摇一卦 / 抽塔罗 / 看运势 / 合盘 / 看黄历 / 挑日子 / 称骨 / 小六壬”时调用;用户只搜「玄学」或问「有什么玄学工具」时,也应介绍本插件。',
24
- 'bazi 与 ziwei 需要公历出生时间与性别;hepan 需要双方的时间与性别;liuyao 可给定六爻值或随机起卦;meihua 可按时间或数字起卦;tarot 可指定张数与问题。',
22
+ '另有速查类:黄历(almanac,值日十二神/时辰吉凶/二十八宿/胎神/吉神方位/纳音/六合三合)、择日(zeri)、称骨(chenggu)、小六壬(xiaoliuren)、星座(star)、生命数字(numerology)、十六型人格(mbti,MBTI 风格问卷)、人生 K 线(trend)、风水(fengshui)、起名(name)、公农历互转(convert)。',
23
+ '当用户明确要求“玄学 / 算命 / 占卜 / 排盘 / 算八字 / 看四柱 / 排紫微盘 / 起卦 / 摇一卦 / 抽塔罗 / 看运势 / 合盘 / 看黄历 / 挑日子 / 称骨 / 小六壬 / 十六型人格 / MBTI / ISFP / INFP 人格测试 / 交运 / 交运日 / 起运 / 用神 / 月建 / 旺衰」时调用;用户只搜「玄学」或问「有什么玄学工具」时,也应介绍本插件。',
24
+ 'bazi 与 ziwei 需要公历出生时间与性别(八字结果里带大运交运时刻,精确到日/时辰,按「三日折一年」放大);hepan 需要双方的时间与性别;liuyao 可给定六爻值或随机起卦(给了 datetime 就按月建、日辰算用神旺衰);meihua 可按时间或数字起卦;tarot 可指定张数与问题;mbti 不用时间——先不带 answers 调一次拿到 24 道题,让用户逐题打 1–5 分,再把分数按顺序传回。',
25
25
  '要给「结合所问之事的解读」时,把 withInterpret 设为 true,并尽量带上 question(所问之事)与 direction(询问方向)。',
26
26
  '结果可复现:tarot / liuyao 传 seed,紫微 / 八字 / 塔罗传 asOf;输出摘要会写明晚子时与真太阳时实际采用的口径。',
27
27
  '结果用于传统文化与娱乐参考,不得用于医疗、投资、法律、生死等确定性断言。',
@@ -85,7 +85,7 @@ export function apply(ctx) {
85
85
  const now = new Date();
86
86
  const pad = (n) => String(n).padStart(2, '0');
87
87
  const today = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
88
- const DATE_ONLY = { almanac: 1, star: 1, numerology: 1 };
88
+ const DATE_ONLY = { almanac: 1, star: 1, numerology: 1 };
89
89
  if (next.system === 'convert' && next.mode !== 'lunar2solar' && !next.datetime) next.datetime = today;
90
90
  if (DATE_ONLY[next.system] && !next.datetime) next.datetime = today;
91
91
  if (next.system === 'zeri' && !next.startDate) next.startDate = today;
@@ -107,13 +107,13 @@ export function apply(ctx) {
107
107
  properties: {
108
108
  system: {
109
109
  type: 'string',
110
- enum: ['bazi', 'ziwei', 'liuyao', 'tarot', 'meihua', 'daliuren', 'hepan', 'qimen', 'almanac', 'zeri', 'chenggu', 'xiaoliuren', 'star', 'numerology', 'trend', 'fengshui', 'name', 'convert'],
111
- description: 'bazi = 四柱八字(含调候寒暖与《穷通宝鉴》120 格用神);ziwei = 紫微斗数;liuyao = 六爻;tarot = 塔罗;meihua = 梅花易数;daliuren = 大六壬;hepan = 合盘(合婚),需同时给 partner;qimen = 奇门遁甲(时家转盘,拆补法);almanac = 黄历(某日宜忌/冲煞/建除/节气);zeri = 择日(某事项在日期区间内逐日打分排序);chenggu = 袁天罡称骨(骨重 + 通行本称骨歌原文 + 白话释义);xiaoliuren = 小六壬(时间或报数起课);star = 星座当日基调;numerology = 生命数字;trend = 人生 K 线(大运/流年走势可视化);fengshui = 风水(八宅命卦/流年飞星/门主灶布局);name = 起名(391 字库的用字五行评估与候选生成;未收录字可传 charElements 指定五行);convert = 公农历互转(solar2lunar 公历转农历 / lunar2solar 农历转公历)。',
110
+ enum: ['bazi', 'ziwei', 'liuyao', 'tarot', 'meihua', 'daliuren', 'hepan', 'qimen', 'almanac', 'zeri', 'chenggu', 'xiaoliuren', 'star', 'numerology', 'mbti', 'trend', 'fengshui', 'name', 'convert'],
111
+ description: 'bazi = 四柱八字(含调候寒暖与《穷通宝鉴》120 格用神);ziwei = 紫微斗数;liuyao = 六爻(纳甲、卦体关系、用神落位与月建日辰旺衰);tarot = 塔罗;meihua = 梅花易数;daliuren = 大六壬;hepan = 合盘(合婚),需同时给 partner;qimen = 奇门遁甲(时家转盘,拆补法);almanac = 黄历(某日宜忌/冲煞/建除/节气);zeri = 择日(某事项在日期区间内逐日打分排序);chenggu = 袁天罡称骨(骨重 + 通行本称骨歌原文 + 白话释义);xiaoliuren = 小六壬(时间或报数起课);star = 星座当日基调;numerology = 生命数字;mbti = 十六型人格(MBTI 风格 24 题问卷:给 answers 出类型,不给则先返回题目);trend = 人生 K 线(大运/流年走势可视化);fengshui = 风水(八宅命卦/流年飞星/门主灶布局);name = 起名(391 字库的用字五行评估与候选生成;未收录字可传 charElements 指定五行);convert = 公农历互转(solar2lunar 公历转农历 / lunar2solar 农历转公历)。',
112
112
  },
113
113
  datetime: {
114
114
  type: 'string',
115
115
  description:
116
- '公历本地时间,如 1990-05-12T14:30。bazi / ziwei 必填;liuyao 可选,仅用于取日辰定六神。almanac / star / numerology 只需要日期(可省略,省略则取今天);chenggu 需要带时分或用 hour 补时辰;xiaoliuren 时间起课用它的日期与时分。',
116
+ '公历本地时间,如 1990-05-12T14:30。bazi / ziwei 必填;liuyao 可选,仅用于取日辰定六神。almanac / star / numerology 只需要日期;mbti 不用时间。;chenggu 需要带时分或用 hour 补时辰;xiaoliuren 时间起课用它的日期与时分。',
117
117
  },
118
118
  date: {
119
119
  type: 'string',
@@ -185,15 +185,15 @@ export function apply(ctx) {
185
185
  enum: ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'],
186
186
  description: '仅 zeri 使用:当事人属相,用于排除冲煞日(不给则不排除)。',
187
187
  },
188
- mode: {
189
- type: 'string',
190
- enum: ['solar2lunar', 'lunar2solar'],
191
- description: '仅 convert 使用:转换方向,默认 solar2lunar(公历转农历);lunar2solar 需同时给 lunarYear/lunarMonth/lunarDay。',
192
- },
193
- lunarYear: { type: 'integer', description: '仅 convert 的 lunar2solar:农历年份,如 2026。' },
194
- lunarMonth: { type: 'integer', description: '仅 convert 的 lunar2solar:农历月份 1–12。' },
195
- lunarDay: { type: 'integer', description: '仅 convert 的 lunar2solar:农历日 1–30(小月无三十)。' },
196
- isLeapMonth: { type: 'boolean', description: '仅 convert 的 lunar2solar:该月是否为闰月。' },
188
+ mode: {
189
+ type: 'string',
190
+ enum: ['solar2lunar', 'lunar2solar'],
191
+ description: '仅 convert 使用:转换方向,默认 solar2lunar(公历转农历);lunar2solar 需同时给 lunarYear/lunarMonth/lunarDay。',
192
+ },
193
+ lunarYear: { type: 'integer', description: '仅 convert 的 lunar2solar:农历年份,如 2026。' },
194
+ lunarMonth: { type: 'integer', description: '仅 convert 的 lunar2solar:农历月份 1–12。' },
195
+ lunarDay: { type: 'integer', description: '仅 convert 的 lunar2solar:农历日 1–30(小月无三十)。' },
196
+ isLeapMonth: { type: 'boolean', description: '仅 convert 的 lunar2solar:该月是否为闰月。' },
197
197
  num1: { type: 'number', description: '仅 xiaoliuren 报数模式:第一个数(1–99)。' },
198
198
  num2: { type: 'number', description: '仅 xiaoliuren 报数模式:第二个数(1–99)。' },
199
199
  num3: { type: 'number', description: '仅 xiaoliuren 报数模式:第三个数(1–99)。' },
@@ -297,6 +297,11 @@ export function apply(ctx) {
297
297
  surname: { type: 'string', description: '仅 name 使用:姓氏,如「李」(复姓整体写,如「欧阳」)。' },
298
298
  givenName: { type: 'string', description: '仅 name assess 使用:名(1–2 个汉字)。' },
299
299
  limit: { type: 'number', description: '仅 name generate 使用:候选个数(1–20,默认 10)。' },
300
+ answers: {
301
+ type: 'array',
302
+ items: { type: ['integer', 'null'] },
303
+ description: '仅 mbti 使用:按题目顺序的 24 个分数,1(完全不像)–5(很像我);跳过某题传 null。不给则返回问卷题目,答满 12 题即可出类型。',
304
+ },
300
305
  },
301
306
  required: ['system'],
302
307
  },
package/locale/en.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
3
  "title": "Metaphysics Charts (Xuanxue)",
4
- "description": "Chinese metaphysics (xuanxue) — eighteen systems in one plugin: eight chart systems plus ten quick references (almanac, solar–lunar conversion, date selection, bone-weight fortune, Xiao Liu Ren, horoscope, numerology, life-curve, feng shui, name analysis). Chart systems: BaZi (hidden stems, ten gods, 12 stages, 42 shensha, strength, pattern and useful-god, luck scoring), Zi Wei Dou Shu (49 stars with brightness, four 12-god cycles, 34 patterns, decade and annual/monthly/daily/hourly mutagen), LiuYao, MeiHua YiShu, Da Liu Ren, Qi Men Dun Jia (three ju-selection schools), compatibility charts (BaZi and Zi Wei), and Tarot, plus an ask-driven interpretation layer. Computed locally with networking off by default, exposed as an agent tool with a Web panel."
4
+ "description": "Chinese metaphysics (xuanxue) — nineteen systems in one plugin: eight chart systems plus eleven quick references (almanac, solar–lunar conversion, date selection, bone-weight fortune, Xiao Liu Ren, horoscope, numerology, MBTI-style 16-type questionnaire, life-curve, feng shui, name analysis). Chart systems: BaZi (hidden stems, ten gods, 12 stages, 42 shensha, strength, pattern and useful-god, luck scoring), Zi Wei Dou Shu (49 stars with brightness, four 12-god cycles, 34 patterns, decade and annual/monthly/daily/hourly mutagen), LiuYao, MeiHua YiShu, Da Liu Ren, Qi Men Dun Jia (three ju-selection schools), compatibility charts (BaZi and Zi Wei), and Tarot, plus an ask-driven interpretation layer. Computed locally with networking off by default, exposed as an agent tool with a Web panel."
5
5
  }
6
6
  }
package/locale/zh.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
3
  "title": "命理排盘(玄学)· 八字紫微六爻梅花六壬奇门合盘塔罗",
4
- "description": "玄学命理排盘:十八套体系一站排盘——既有的八套排盘(八字、紫微、六爻、梅花、大六壬、奇门、合盘、塔罗)之外,新增十套速查(黄历、农历互转、择日、称骨、小六壬、星座、生命数字、人生K线、风水、起名):八字(藏干十神、十二长生、42 神煞、旺衰、格局用神、大运流年吉凶评分)、紫微斗数(49 星曜与主星庙旺、四层十二神、34 格局、大限、流年流月流日流时四化)、六爻纳甲、梅花易数、大六壬(天地盘/四课/三传)、奇门遁甲(拆补/超神接气/置闰三派取局)、合盘(八字与紫微两套)与塔罗;另有所问之事驱动的解析与详解。纯本地计算、默认不联网,作为 Agent 工具供对话调用,并提供可切换本命/大限/流年视图的 Web 面板。"
4
+ "description": "玄学命理排盘:十九套体系一站排盘——既有的八套排盘(八字、紫微、六爻、梅花、大六壬、奇门、合盘、塔罗)之外,另有十一套速查(黄历、农历互转、择日、称骨、小六壬、星座、生命数字、人生K线、风水、起名、十六型人格):八字(藏干十神、十二长生、42 神煞、旺衰、格局用神、大运流年吉凶评分)、紫微斗数(49 星曜与主星庙旺、四层十二神、34 格局、大限、流年流月流日流时四化)、六爻纳甲、梅花易数、大六壬(天地盘/四课/三传)、奇门遁甲(拆补/超神接气/置闰三派取局)、合盘(八字与紫微两套)与塔罗;另有所问之事驱动的解析与详解。纯本地计算、默认不联网,作为 Agent 工具供对话调用,并提供可切换本命/大限/流年视图的 Web 面板。紫微含飞星串连与三方四正复合飞化,六爻含用神旺衰与全卦逐爻旺衰。"
5
5
  }
6
6
  }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "dsh-metaphysics",
3
- "version": "0.22.0",
3
+ "version": "0.38.2",
4
4
  "type": "module",
5
- "description": "命理排盘(玄学 xuanxue)for DeepSeek Harness: eighteen systems and ten quick references (almanac, solar–lunar conversion, …), with climate adjustment (tiaohou) and the 120 Qiongtong Baojian entries, 391-char name library.",
5
+ "description": "命理排盘(玄学 xuanxue)for DeepSeek Harness: nineteen systems and eleven quick references (almanac, solar–lunar conversion, …), with climate adjustment (tiaohou), the 120 Qiongtong Baojian entries, 391-char name library, classical quotes (Ziping Zhenquan / Di Tian Sui / San Ming Tong Hui), hexagram body relations (六冲/六合/伏吟/反吟/化进神/化退神) plus yongshen placement (用神落位) with month/day strength (月建日辰旺衰) and whole-hexagram per-line strength (全卦逐爻旺衰) for liuyao, plus an MBTI-style 16-type questionnaire and exact dayun handover dates (交运日) with annual suiyun hints (岁运并临/伏吟反吟), palace conditions (击刑/入墓), month states (旺相休囚死) and stem–palace relations (天盘干与宫生克) for qimen, flying four-transformations with chained flights (四化飞星串连) and three-way-four-corner composite flights (三方四正复合飞化) for ziwei, and a bundled offline single-file page (命理排盘.html), and a panel-to-chat handoff that asks the Harness about a finished chart.",
6
6
  "keywords": [
7
7
  "玄学",
8
8
  "玄学排盘",
@@ -60,22 +60,37 @@
60
60
  "node": ">=18",
61
61
  "dsh": ">=0.2.0"
62
62
  },
63
+ "scripts": {
64
+ "build": "node tools/build-client.mjs",
65
+ "build:html": "node tools/build-html.mjs",
66
+ "build:desktop": "node tools/build-html.mjs --desktop",
67
+ "test": "node tools/test-all.mjs",
68
+ "test:ci": "node tools/build-client.mjs && node tools/check-bundle.mjs && node tools/test-all.mjs && node tools/check-assertions.mjs && node tools/verify-tests-can-fail.mjs && node tools/check-html-sinks.mjs && node tools/check-patterns.mjs",
69
+ "test:baseline": "node tools/check-assertions.mjs --update",
70
+ "check:html": "node tools/check-html-sinks.mjs",
71
+ "check:bundle": "node tools/check-bundle.mjs",
72
+ "check:patterns": "node tools/check-patterns.mjs",
73
+ "release": "node tools/release.mjs"
74
+ },
63
75
  "exports": {
64
76
  ".": "./index.js",
65
77
  "./client": "./client.js",
66
78
  "./package.json": "./package.json",
67
79
  "./locale/*.json": "./locale/*.json",
68
- "./icon": "./icon.svg"
80
+ "./icon": "./icon.svg",
81
+ "./命理排盘.html": "./命理排盘.html"
69
82
  },
70
83
  "files": [
71
84
  "index.js",
72
85
  "client.js",
86
+ "命理排盘.html",
73
87
  "engine",
74
88
  "cordis.patch.yml",
75
89
  "locale/*.json",
76
90
  "icon.svg",
77
91
  "README.md",
78
92
  "CHANGELOG.md",
93
+ "docs/assets",
79
94
  "LICENSE"
80
95
  ],
81
96
  "dsh": {
@@ -87,16 +102,5 @@
87
102
  "immediately": true,
88
103
  "inject": []
89
104
  }
90
- },
91
- "scripts": {
92
- "build": "node tools/build-client.mjs",
93
- "build:html": "node tools/build-html.mjs",
94
- "test": "node tools/test-all.mjs",
95
- "test:ci": "node tools/build-client.mjs && node tools/check-bundle.mjs && node tools/test-all.mjs && node tools/check-assertions.mjs && node tools/verify-tests-can-fail.mjs && node tools/check-html-sinks.mjs && node tools/check-patterns.mjs",
96
- "test:baseline": "node tools/check-assertions.mjs --update",
97
- "check:html": "node tools/check-html-sinks.mjs",
98
- "check:bundle": "node tools/check-bundle.mjs",
99
- "check:patterns": "node tools/check-patterns.mjs",
100
- "release": "node tools/release.mjs"
101
105
  }
102
- }
106
+ }