dsh-metaphysics 0.56.0 → 0.58.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 +103 -1
- package/README.md +26 -9
- package/client.almanac.js +66 -61
- package/client.bazi.js +98 -91
- package/client.chenggu.js +68 -63
- package/client.convert.js +68 -63
- package/client.daliuren.js +104 -97
- package/client.fengshui.js +65 -60
- package/client.hepan.js +99 -92
- package/client.js +392 -267
- package/client.liuyao.js +101 -94
- package/client.mbti.js +66 -61
- package/client.name.js +68 -63
- package/client.numerology.js +66 -61
- package/client.qimen.js +104 -97
- package/client.star.js +66 -61
- package/client.tarot.js +99 -94
- package/client.trend.js +104 -97
- package/client.xiaoliuren.js +66 -61
- package/client.zeri.js +66 -61
- package/client.ziwei.js +98 -91
- package/engine/bridge.js +211 -0
- package/engine/citations.js +603 -320
- package/engine/diff.js +59 -0
- package/engine/fengshui.js +718 -718
- package/engine/geju.js +16 -0
- package/engine/handle.js +192 -0
- package/engine/hepan.js +43 -0
- package/engine/index.js +168 -51
- package/engine/interpret-knowledge.js +3 -2
- package/engine/interpret-plain.js +4 -1
- package/engine/interpret.js +7 -3
- package/engine/qimen-ganying.js +134 -134
- package/engine/qimen-interpret.js +233 -233
- package/engine/revise.js +162 -0
- package/engine/trace.js +493 -456
- package/engine/zeri.js +89 -13
- package/index.js +59 -6
- package/package.json +6 -3
- package//345/221/275/347/220/206/346/216/222/347/233/230.html +3548 -1943
package/engine/index.js
CHANGED
|
@@ -5,12 +5,15 @@ import { buildZiwei, BRIGHTNESS, flowOf, asOfParts, ZIWEI_SCHOOL_DEFAULTS } from
|
|
|
5
5
|
import { drawTarot } from './tarot.js';
|
|
6
6
|
import { buildMeihua } from './meihua.js';
|
|
7
7
|
import { buildDaliuren } from './daliuren.js';
|
|
8
|
-
import { buildHepan } from './hepan.js';
|
|
8
|
+
import { buildHepan, tripleOf } from './hepan.js';
|
|
9
9
|
import { buildZiweiHepan } from './ziwei-hepan.js';
|
|
10
10
|
import { buildQimen, buildSnapshot } from './qimen.js';
|
|
11
11
|
import { geocodeAddress, resolveAddress } from './geo.js';
|
|
12
12
|
import { toJDN, ganzhiName, dayGanzhiIndex } from './calendar.js';
|
|
13
13
|
import { randomOf, isSeed } from './random.js';
|
|
14
|
+
import { encodeHandle, decodeHandle, resolveHandle } from './handle.js';
|
|
15
|
+
import { askLink, parseAskLink, formOf, restNote, askPackages } from './bridge.js';
|
|
16
|
+
import { parseRevision, displayValue } from './revise.js';
|
|
14
17
|
import { interpret, DIRECTIONS, DIRECTION_DEFAULT } from './interpret.js';
|
|
15
18
|
import { followup, askPrompt } from './followup.js';
|
|
16
19
|
import { crossCheck, crossText, crossSection } from './crosscheck.js';
|
|
@@ -25,12 +28,12 @@ import { buildNumerology } from './numerology.js';
|
|
|
25
28
|
import { buildMbti, mbtiPaper } from './mbti.js';
|
|
26
29
|
import { buildConvert } from './convert.js';
|
|
27
30
|
import { classicsFor, classicsText, suiyunClassicOf, classicOf, CLASSIC_BOOKS } from './classics.js';
|
|
28
|
-
import { diffObjects, summarize, sortDiffs, labelOf, rootOf, categoryOf, formatValue, CALIBER_SWITCHES } from './diff.js';
|
|
31
|
+
import { diffObjects, summarize, sortDiffs, labelOf, rootOf, categoryOf, formatValue, CALIBER_SWITCHES, viewRows } from './diff.js';
|
|
29
32
|
import { canonicalJson, fingerprintOf } from './fingerprint.js';
|
|
30
33
|
import { buildTrend } from './trend.js';
|
|
31
34
|
import { buildFengshui } from './fengshui.js';
|
|
32
35
|
import { buildName } from './name.js';
|
|
33
|
-
import { buildTrace, SYSTEM_LABEL } from './trace.js';
|
|
36
|
+
import { buildTrace, traceMarkdown, SYSTEM_LABEL } from './trace.js';
|
|
34
37
|
import { fail } from './fail.js';
|
|
35
38
|
import { assertCivil } from './validate.js';
|
|
36
39
|
|
|
@@ -139,10 +142,14 @@ function baziText(r) {
|
|
|
139
142
|
? ` 有争议:${ysd.map((d) => `${d.element}(${d.favorRole};${d.climate}盘调候忌${d.element})`).join('、')}`
|
|
140
143
|
: '';
|
|
141
144
|
const disEls = new Set(ysd.map((d) => d.element));
|
|
145
|
+
const ysn = (r.frame && r.frame.yongshen && r.frame.yongshen.neutral) || [];
|
|
146
|
+
const neuText = ysn.length
|
|
147
|
+
? ` 中性偏忌:${ysn.map((n) => `${n.element} ${n.weight} 分`).join('、')}(近零,不作实忌)`
|
|
148
|
+
: '';
|
|
142
149
|
const gejuLine = r.frame ? [
|
|
143
150
|
`格局:${r.frame.primary ? `${r.frame.primary.name}(${r.frame.primary.evidence})` : '—'}`,
|
|
144
151
|
` ${r.frame.geju.map((g) => `${g.name}[${g.kind}${g.status ? `·${g.status}` : ''}]`).join(' ')}`,
|
|
145
|
-
`用神:喜${r.frame.yongshen.favor.join('')}(${r.frame.yongshen.favorTenGods.join('、')}) 忌${r.frame.yongshen.avoid.join('')}(${r.frame.yongshen.avoidTenGods.join('、')})${disText} ${r.frame.yongshen.method}`,
|
|
152
|
+
`用神:喜${r.frame.yongshen.favor.join('')}(${r.frame.yongshen.favorTenGods.join('、')}) 忌${r.frame.yongshen.avoid.join('')}(${r.frame.yongshen.avoidTenGods.join('、')})${disText}${neuText} ${r.frame.yongshen.method}`,
|
|
146
153
|
` ${r.frame.yongshen.detail}`,
|
|
147
154
|
`寒暖:${r.climate ? `${r.climate.label}(${(r.climate.evidence || []).join('、')})${r.climate.need ? ` 调候取${r.climate.need.stem}${r.climate.need.element} 忌${r.climate.avoidElement}${disEls.has(r.climate.avoidElement) ? '(有争议)' : ''}` : ''}` : '—'}` +
|
|
148
155
|
(r.frame.yongshen.qt ? ` 穷通:${r.frame.yongshen.qt.month}${r.frame.yongshen.qt.stem}取${r.frame.yongshen.qt.yong.join('、')}(首取${r.frame.yongshen.qt.primary})` : ''),
|
|
@@ -291,6 +298,26 @@ function qimenText(r) {
|
|
|
291
298
|
].join('\n');
|
|
292
299
|
}
|
|
293
300
|
|
|
301
|
+
function tripleText(t) {
|
|
302
|
+
if (!t || !Array.isArray(t.pairs) || !t.pairs.length) return [];
|
|
303
|
+
const lines = [
|
|
304
|
+
'【三方合盘】三对两两并列,不合成「三人总分」',
|
|
305
|
+
...t.pairs.map((p) => `· ${p.a}–${p.b}:${p.level || '—'}(${p.total == null ? '—' : `${p.total}/100`})`),
|
|
306
|
+
];
|
|
307
|
+
if (t.best) {
|
|
308
|
+
// 差 1–2 分时点名「最顺/最需磨合」是假精确:三对分数接近就直说接近,不排名
|
|
309
|
+
if (t.spread >= 3) {
|
|
310
|
+
lines.push(` 最顺:${t.best.a}–${t.best.b}(${t.best.total}/100)`
|
|
311
|
+
+ (t.hardest ? `;最需磨合:${t.hardest.a}–${t.hardest.b}(${t.hardest.total}/100)` : ''));
|
|
312
|
+
} else {
|
|
313
|
+
lines.push(` 三对分数接近(最高与最低相差 ${t.spread} 分),不排名`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (t.focus && t.focus.spread >= 3) lines.push(` 差异最大的一维:${t.focus.label}(三对相差 ${t.focus.spread} 分)`);
|
|
317
|
+
if (t.note) lines.push(`※ ${t.note}`);
|
|
318
|
+
return lines;
|
|
319
|
+
}
|
|
320
|
+
|
|
294
321
|
function hepanText(r) {
|
|
295
322
|
if (r.chart === 'ziwei') {
|
|
296
323
|
const d = (x) => `${x.label}:${x.score >= 0 ? '+' : ''}${x.score} ${x.text}`;
|
|
@@ -300,6 +327,7 @@ function hepanText(r) {
|
|
|
300
327
|
`对方 命宫 ${r.b.soul.branch}(${r.b.soulStars.join('、') || '无主星'}) 夫妻 ${r.b.spouseStars.join('、') || '无主星'} ${r.b.bureau}`,
|
|
301
328
|
...r.dimensions.map(d),
|
|
302
329
|
...r.interactions.map((h) => ` · ${h.text}`),
|
|
330
|
+
...tripleText(r.triple),
|
|
303
331
|
...r.notes.map((n) => `※ ${n}`),
|
|
304
332
|
].join('\n');
|
|
305
333
|
}
|
|
@@ -323,6 +351,7 @@ function hepanText(r) {
|
|
|
323
351
|
`年命纳音:${r.detail.nayin.a} / ${r.detail.nayin.b}(${r.detail.nayin.label})——${r.detail.nayin.text}`,
|
|
324
352
|
`吉凶象:吉 ${r.detail.tally.good} / 凶 ${r.detail.tally.bad}(${r.detail.tally.lean};分档只数象,总分以上面三维度为准)`,
|
|
325
353
|
] : []),
|
|
354
|
+
...tripleText(r.triple),
|
|
326
355
|
...r.notes.map((n) => `※ ${n}`),
|
|
327
356
|
].join('\n');
|
|
328
357
|
}
|
|
@@ -484,7 +513,7 @@ function jsonSafe(value) {
|
|
|
484
513
|
// 只收影响盘面的参数:地址换成有效经度后不再把原文算进去,问事/方向按体系保留。
|
|
485
514
|
const SHADOW_IGNORE = new Set([
|
|
486
515
|
'shadow', 'shadowVersion', 'diff', 'trace', 'traceError', 'withInterpret', 'cross', 'verifyPast', 'rectify', 'events',
|
|
487
|
-
'geocode', 'ask', 'followup', 'caliber', 'seed', 'asOf',
|
|
516
|
+
'geocode', 'ask', 'followup', 'caliber', 'seed', 'asOf', 'handle', 'revise',
|
|
488
517
|
]);
|
|
489
518
|
|
|
490
519
|
const num6 = (n) => {
|
|
@@ -553,11 +582,14 @@ function shadowParams(args, result) {
|
|
|
553
582
|
};
|
|
554
583
|
}
|
|
555
584
|
if (system === 'hepan') {
|
|
556
|
-
|
|
585
|
+
const params = {
|
|
557
586
|
chart: args.chart === 'ziwei' ? 'ziwei' : 'bazi',
|
|
558
587
|
a: shadowPerson({ ...args, datetime: args.datetime }),
|
|
559
588
|
b: shadowPerson(args.partner || {}),
|
|
560
589
|
};
|
|
590
|
+
// 第三方进指纹:同一对加上不同的第三人,是另一组盘
|
|
591
|
+
if (args.partner2) params.c = shadowPerson(args.partner2);
|
|
592
|
+
return params;
|
|
561
593
|
}
|
|
562
594
|
|
|
563
595
|
// 其余体系:只剔除解析/附加模块参数,其余原样归一化
|
|
@@ -625,11 +657,11 @@ export function chartFingerprint(args = {}, opts = {}) {
|
|
|
625
657
|
}
|
|
626
658
|
|
|
627
659
|
const SHADOW_DIFF_IGNORE = new Set([
|
|
628
|
-
'shadow', 'trace', 'traceError', 'interpret', 'summary', 'classics', 'suiyunClassic', 'renyuanClassic', 'cross',
|
|
660
|
+
'shadow', 'trace', 'traceText', 'traceError', 'interpret', 'summary', 'classics', 'suiyunClassic', 'renyuanClassic', 'cross',
|
|
629
661
|
'past', 'rectify', 'followup', 'caliber', 'input', 'reading', 'knowledge', 'outline',
|
|
630
662
|
'sections', 'answer', 'plain', 'tables', 'glossary', 'caveats', 'lead', 'dimensions',
|
|
631
663
|
'moduleType', 'technique', 'disclaimer', 'ask', 'followups', 'knowledgeCount', 'title',
|
|
632
|
-
'systemLabel',
|
|
664
|
+
'systemLabel', 'handle', 'handleError', 'revision',
|
|
633
665
|
]);
|
|
634
666
|
|
|
635
667
|
function shadowChart(result) {
|
|
@@ -693,9 +725,34 @@ export function shadowDiff(previous, current, opts = {}) {
|
|
|
693
725
|
* @param {object} args
|
|
694
726
|
* @param {'bazi'|'ziwei'|'liuyao'} args.system
|
|
695
727
|
* @param {string} [args.datetime]
|
|
728
|
+
* @param {string} [args.handle] 上次结果里的句柄;给了它就可以只传增量参数(如 asOf、direction、system)
|
|
696
729
|
*/
|
|
697
|
-
export function compute(
|
|
730
|
+
export function compute(input = {}) {
|
|
731
|
+
// 句柄先并回参数:后面的代码只看见一份完整参数,不必到处判 handle
|
|
732
|
+
let args = resolveHandle(input);
|
|
733
|
+
// 一句话改参(C2):把「换成紫微看 2030 年事业」翻成补丁再排盘;识别不到就原样排,
|
|
734
|
+
// 绝不猜。改了哪些、没认哪些都随结果回传,便于核对。
|
|
735
|
+
let revision;
|
|
736
|
+
if (typeof args.revise === 'string' && args.revise.trim()) {
|
|
737
|
+
const rev = parseRevision(args.revise);
|
|
738
|
+
const before = { ...args };
|
|
739
|
+
args = { ...args, ...rev.patch };
|
|
740
|
+
revision = {
|
|
741
|
+
text: rev.text,
|
|
742
|
+
applied: rev.labels.map((l) => {
|
|
743
|
+
const from = before[l.key] === undefined ? null : before[l.key];
|
|
744
|
+
return { ...l, from, fromDisplay: displayValue(l.key, from) };
|
|
745
|
+
}),
|
|
746
|
+
ignored: rev.ignored,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
// partner2: null 视同未传:先归一化再排盘,否则同一对盘会因为显式 null 多出一个句柄
|
|
750
|
+
if (args.partner2 === null) {
|
|
751
|
+
args = { ...args };
|
|
752
|
+
delete args.partner2;
|
|
753
|
+
}
|
|
698
754
|
const r = jsonSafe(computeRaw(args));
|
|
755
|
+
if (revision) r.revision = revision;
|
|
699
756
|
if (r && r.system === 'bazi') {
|
|
700
757
|
r.classics = classicsFor(r);
|
|
701
758
|
const ct = classicsText(r.classics);
|
|
@@ -788,7 +845,11 @@ export function compute(args = {}) {
|
|
|
788
845
|
if (args.trace === true) {
|
|
789
846
|
try {
|
|
790
847
|
const layers = buildTrace(r, { direction: args.direction, gender: args.gender });
|
|
791
|
-
if (layers)
|
|
848
|
+
if (layers) {
|
|
849
|
+
r.trace = layers;
|
|
850
|
+
// 同一份层另出一份 Markdown:贴进对话/文档时表格不会散架,内容与 r.trace 同源
|
|
851
|
+
r.traceText = traceMarkdown(layers, { system: r.system });
|
|
852
|
+
}
|
|
792
853
|
} catch (e) {
|
|
793
854
|
r.traceError = String((e && e.message) || e);
|
|
794
855
|
}
|
|
@@ -801,6 +862,13 @@ export function compute(args = {}) {
|
|
|
801
862
|
r.shadow = { error: String((e && e.message) || e) };
|
|
802
863
|
}
|
|
803
864
|
}
|
|
865
|
+
// 排盘句柄:把这张盘的参数压成短串;下一次追问传 handle + 增量即可,不必重报出生信息
|
|
866
|
+
try {
|
|
867
|
+
const h = encodeHandle(args);
|
|
868
|
+
if (h) r.handle = h;
|
|
869
|
+
} catch (e) {
|
|
870
|
+
r.handleError = String((e && e.message) || e);
|
|
871
|
+
}
|
|
804
872
|
return r;
|
|
805
873
|
}
|
|
806
874
|
|
|
@@ -864,11 +932,12 @@ export function caliberCompare(args = {}, opts = {}) {
|
|
|
864
932
|
const alt = sw.alt(current);
|
|
865
933
|
let diffs = [];
|
|
866
934
|
let error = '';
|
|
935
|
+
let cur = null;
|
|
936
|
+
let altRes = null;
|
|
867
937
|
try {
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
);
|
|
938
|
+
cur = compute({ ...base, [sw.key]: current });
|
|
939
|
+
altRes = compute({ ...base, [sw.key]: alt });
|
|
940
|
+
diffs = diffObjects(cur, altRes);
|
|
872
941
|
} catch (e) {
|
|
873
942
|
error = (e && e.message) || String(e);
|
|
874
943
|
}
|
|
@@ -896,6 +965,7 @@ export function caliberCompare(args = {}, opts = {}) {
|
|
|
896
965
|
altLabel: sw.label(alt),
|
|
897
966
|
total: diffs.length,
|
|
898
967
|
summary: error ? '' : summarize(diffs),
|
|
968
|
+
views: error ? [] : viewRows(system, cur, altRes),
|
|
899
969
|
roots,
|
|
900
970
|
categories,
|
|
901
971
|
error,
|
|
@@ -1008,31 +1078,42 @@ function computeRaw(args = {}) {
|
|
|
1008
1078
|
if (!partner.datetime) {
|
|
1009
1079
|
throw fail('E_PARTNER', '缺少 partner.datetime(对方的公历出生时间),例如 partner: {"datetime":"1992-03-03T10:00","gender":"female"}');
|
|
1010
1080
|
}
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1081
|
+
const partner2 = args.partner2;
|
|
1082
|
+
if (partner2 !== undefined && partner2 !== null) {
|
|
1083
|
+
if (typeof partner2 !== 'object' || Array.isArray(partner2)) {
|
|
1084
|
+
throw fail('E_PARTNER', 'partner2 需要 { datetime, gender, address? };不想看三方就整段省略(null 视同未传)');
|
|
1085
|
+
}
|
|
1086
|
+
if (!partner2.datetime) {
|
|
1087
|
+
throw fail('E_PARTNER', '缺少 partner2.datetime(第三方的公历出生时间),例如 partner2: {"datetime":"1988-09-09T08:00","gender":"male"}');
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1013
1090
|
const chart = args.chart === 'ziwei' ? 'ziwei' : 'bazi';
|
|
1014
1091
|
// 性别决定双方大运/大限顺逆,两边都不能用默认值
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1092
|
+
const sideOf = (src, who) => {
|
|
1093
|
+
const dt = parseDateTime(src.datetime);
|
|
1094
|
+
return {
|
|
1095
|
+
...dt,
|
|
1096
|
+
gender: requireGender(src.gender, who),
|
|
1097
|
+
trueSolar: src.trueSolar,
|
|
1098
|
+
lateZi: src.lateZi,
|
|
1099
|
+
dst: src.dst !== false,
|
|
1100
|
+
address: typeof src.address === 'string' ? src.address : undefined,
|
|
1101
|
+
longitude: typeof src.longitude === 'number' ? src.longitude : undefined,
|
|
1102
|
+
geo: src.geo && typeof src.geo === 'object' ? src.geo : undefined,
|
|
1103
|
+
};
|
|
1024
1104
|
};
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1105
|
+
const sideA = sideOf(args, '你(主方)');
|
|
1106
|
+
const sideB = sideOf(partner, '对方');
|
|
1107
|
+
const build = (x, y) => (chart === 'ziwei' ? buildZiweiHepan({ a: x, b: y }) : buildHepan({ a: x, b: y }));
|
|
1108
|
+
const result = build(sideA, sideB);
|
|
1109
|
+
if (partner2) {
|
|
1110
|
+
const sideC = sideOf(partner2, '第三方');
|
|
1111
|
+
result.triple = tripleOf([
|
|
1112
|
+
{ key: 'a-b', a: '你', b: '对方', result },
|
|
1113
|
+
{ key: 'a-c', a: '你', b: '第三方', result: build(sideA, sideC) },
|
|
1114
|
+
{ key: 'b-c', a: '对方', b: '第三方', result: build(sideB, sideC) },
|
|
1115
|
+
]);
|
|
1116
|
+
}
|
|
1036
1117
|
return { ...result, summary: hepanText(result) };
|
|
1037
1118
|
}
|
|
1038
1119
|
if (system === 'meihua') {
|
|
@@ -1119,16 +1200,23 @@ function computeRaw(args = {}) {
|
|
|
1119
1200
|
return { ...result, summary: almanacText(result) };
|
|
1120
1201
|
}
|
|
1121
1202
|
if (system === 'zeri') {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1203
|
+
const candMode = args.candidates !== undefined && args.candidates !== null;
|
|
1204
|
+
// startDate 必须显式:择日要「从哪天起看」,缺了不能拿本机今天静默代填;候选日模式改用 candidates
|
|
1205
|
+
if (!candMode && (typeof args.startDate !== 'string' || !args.startDate.trim())) {
|
|
1206
|
+
throw fail('E_INPUT', '择日需要 startDate(公历 YYYY-MM-DD,起算日);可另给 days(1–60,默认 30)与 shengXiao(当事人属相)。只想比几天,改给 candidates: ["2026-12-01","2026-12-08"]');
|
|
1207
|
+
}
|
|
1208
|
+
let result;
|
|
1209
|
+
try {
|
|
1210
|
+
result = buildZeri({
|
|
1211
|
+
task: args.task,
|
|
1212
|
+
startDate: args.startDate,
|
|
1213
|
+
days: args.days,
|
|
1214
|
+
shengXiao: args.shengXiao,
|
|
1215
|
+
candidates: args.candidates,
|
|
1216
|
+
});
|
|
1217
|
+
} catch (e) {
|
|
1218
|
+
throw fail('E_INPUT', (e && e.message) || String(e));
|
|
1125
1219
|
}
|
|
1126
|
-
const result = buildZeri({
|
|
1127
|
-
task: args.task,
|
|
1128
|
-
startDate: args.startDate,
|
|
1129
|
-
days: args.days,
|
|
1130
|
-
shengXiao: args.shengXiao,
|
|
1131
|
-
});
|
|
1132
1220
|
return { ...result, summary: zeriText(result) };
|
|
1133
1221
|
}
|
|
1134
1222
|
if (system === 'chenggu') {
|
|
@@ -1318,16 +1406,27 @@ function almanacText(r) {
|
|
|
1318
1406
|
|
|
1319
1407
|
/** 择日文本 */
|
|
1320
1408
|
function zeriText(r) {
|
|
1321
|
-
const
|
|
1322
|
-
const
|
|
1409
|
+
const cand = r.compare && r.compare.mode === 'candidates';
|
|
1410
|
+
const head = cand
|
|
1411
|
+
? `【择日·${r.meta.task}】候选 ${r.meta.days} 天:${r.meta.candidates.join('、')}${r.meta.shengXiao ? ` 当事人属${r.meta.shengXiao}` : '(未给属相,未做冲煞排除)'}`
|
|
1412
|
+
: `【择日·${r.meta.task}】${r.meta.startDate} 起 ${r.meta.days} 天${r.meta.shengXiao ? ` 当事人属${r.meta.shengXiao}` : '(未给属相,未做冲煞排除)'}`;
|
|
1413
|
+
const top = r.days.slice().sort((a, b) => b.score - a.score).slice(0, cand ? 12 : 5)
|
|
1323
1414
|
.map((d) => `· ${d.date} ${d.weekday} ${d.verdict}(${d.score}分) 宜${d.yi.slice(0, 3).join('/')} ${d.reasons.join(';') || '无特别加减分'}`);
|
|
1415
|
+
const bestLine = cand
|
|
1416
|
+
? (r.compare.best
|
|
1417
|
+
? `这一组里最优:${r.compare.best.date}(${r.compare.best.score}分,${r.compare.best.verdict})`
|
|
1418
|
+
+ (r.compare.best.ties.length > 1 ? `;同分:${r.compare.best.ties.filter((d) => d !== r.compare.best.date).join('、')}` : '')
|
|
1419
|
+
: '这一组都因冲属相被排除,没有可用的日子')
|
|
1420
|
+
: `推荐日:${r.best.length ? r.best.join('、') : '本期无(都不够推荐分)'}`;
|
|
1324
1421
|
return [
|
|
1325
1422
|
head,
|
|
1326
|
-
|
|
1423
|
+
bestLine,
|
|
1424
|
+
`推荐日:${r.best.length ? r.best.join('、') : '无'}`,
|
|
1327
1425
|
`可用日:${r.usable.length ? r.usable.join('、') : '无'}`,
|
|
1328
1426
|
`回避日:${r.avoid.length ? r.avoid.slice(0, 6).join('、') : '无'}`,
|
|
1329
|
-
'逐日排序:',
|
|
1427
|
+
cand ? '候选日逐日:' : '逐日排序:',
|
|
1330
1428
|
...top,
|
|
1429
|
+
...(cand ? [`比较口径:${r.compare.note}`] : []),
|
|
1331
1430
|
`口径:${r.meta.scope}`,
|
|
1332
1431
|
].join('\n');
|
|
1333
1432
|
}
|
|
@@ -1551,6 +1650,17 @@ export function renderText(result) {
|
|
|
1551
1650
|
+ (s.reproducible === false ? `\n ⚠ 不可复算:${s.reason}` : '')
|
|
1552
1651
|
+ (s.reproducible === true && s.asOfPinned === false && (s.system === 'bazi' || s.system === 'ziwei') ? '\n 提示:未固定 asOf,流年/流月随「此刻」变化;要比对请传 asOf。' : ''));
|
|
1553
1652
|
}
|
|
1653
|
+
// 一句话改参的回显:改了哪些、没认哪些,都摆出来让人核对,而不是悄悄按新参数排
|
|
1654
|
+
if (result.revision && ((result.revision.applied || []).length || (result.revision.ignored || []).length)) {
|
|
1655
|
+
const rev = result.revision;
|
|
1656
|
+
const rows = (rev.applied || []).map((a) => `${a.label}:${a.fromDisplay == null ? '(未设)' : a.fromDisplay} → ${a.display}`);
|
|
1657
|
+
parts.push(`【改参】${rev.text}${rows.length ? `\n ${rows.join(';')}` : '\n 没有识别到可改的参数,仍按原参数排盘'}`
|
|
1658
|
+
+ ((rev.ignored || []).length ? `\n 未处理:${rev.ignored.join(';')}` : ''));
|
|
1659
|
+
}
|
|
1660
|
+
// 句柄放进文本:模型看到的是这段摘要,不给它就没法在下一轮只传增量
|
|
1661
|
+
if (typeof result.handle === 'string' && result.handle) {
|
|
1662
|
+
parts.push(`【排盘句柄】${result.handle}\n 追问同一张盘:传 handle + 增量参数(asOf / direction / question,或换 system 看另一套盘),不必重报出生信息。`);
|
|
1663
|
+
}
|
|
1554
1664
|
if (Array.isArray(result.trace) && result.trace.length) {
|
|
1555
1665
|
parts.push(`【推导链】${SYSTEM_LABEL[result.system] || result.system} · ${result.trace.length} 层\n`
|
|
1556
1666
|
+ result.trace.map((t, i) => `${i + 1}. ${t.field}|${t.result}\n 规则:${t.rule} 出处:${t.source}`).join('\n'));
|
|
@@ -1566,7 +1676,11 @@ export function renderText(result) {
|
|
|
1566
1676
|
+ c.switches.map((s) => {
|
|
1567
1677
|
if (s.error) return `· ${s.title}:未能对照(${s.error})`;
|
|
1568
1678
|
if (!s.total) return `· ${s.title}:${s.currentLabel} → ${s.altLabel},本盘无变化`;
|
|
1569
|
-
|
|
1679
|
+
const changed = (Array.isArray(s.views) ? s.views : []).filter((v) => v.changed);
|
|
1680
|
+
const side = changed.length
|
|
1681
|
+
? `\n 并排:${changed.map((v) => `${v.label} ${v.current} → ${v.alt}`).join(';')}`
|
|
1682
|
+
: '';
|
|
1683
|
+
return `· ${s.title}:${s.currentLabel} → ${s.altLabel}\n ${s.summary}${side}`;
|
|
1570
1684
|
}).join('\n'));
|
|
1571
1685
|
}
|
|
1572
1686
|
if (result.followup) {
|
|
@@ -1598,7 +1712,10 @@ export { pastSignals, verifyFit, rectifyBirth };
|
|
|
1598
1712
|
export { crossCheck, crossText, crossSection };
|
|
1599
1713
|
export { buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buildNumerology, buildConvert };
|
|
1600
1714
|
export { buildTrend, buildFengshui, buildName };
|
|
1601
|
-
export { buildTrace };
|
|
1715
|
+
export { buildTrace, traceMarkdown };
|
|
1716
|
+
export { encodeHandle, decodeHandle, resolveHandle };
|
|
1717
|
+
// C3 对话桥替代:深链编解码、表单还原、三档复制包(面板与独立页共用一份)
|
|
1718
|
+
export { askLink, parseAskLink, formOf, restNote, askPackages };
|
|
1602
1719
|
|
|
1603
1720
|
|
|
1604
1721
|
|
|
@@ -25,7 +25,8 @@ export const KNOWLEDGE = [
|
|
|
25
25
|
system: 'bazi', dims: ['overall', 'career'],
|
|
26
26
|
gist: '天干是露在外面的样子,地支是藏在地下的根。',
|
|
27
27
|
detail: '同一个五行,透在天干叫「显」,扎在地支叫「有根」。只有天干没有地支,是看着有、使不上劲;只有地支不通天干,是有实力、不显眼。判断一个人能不能扛事,看的就是根有多深。',
|
|
28
|
-
source: '
|
|
28
|
+
source: '《滴天髓·干支总论》「天全一气,不可使地德莫之载;地全三物,不可使天道莫之容」',
|
|
29
|
+
note: '常被署给《滴天髓》的「地支所藏之干,本静以待用,透出干头,则显其用矣。故干以通根为美,支以透出为贵」,出自《子平真诠》卷一论十干十二支的注文——滴天髓底本与沈孝瞻原文里都查不到这句,注文自己引的才是上面那句滴天髓。所以本卡引可核的原文,注文只作说明。',
|
|
29
30
|
status: 'settled',
|
|
30
31
|
},
|
|
31
32
|
{
|
|
@@ -372,7 +373,7 @@ export const KNOWLEDGE = [
|
|
|
372
373
|
detail: '进神退神本身只说明这一爻的向外趋势:用神化进为得力,忌神化进则为患加剧;用神化退是力衰,忌神化退反而是解脱。传统还要看它在本月令衰旺、有没有日辰生扶,空亡或受克时进者未必能进。本插件把进退与爻位标出来,再按月建五态给一档力重——得令则进得动、退得慢,失令则进得虚、退得实,月破压过一切;只给档位,不折成加权分数,吉凶仍落在用神与忌神那一层判。',
|
|
373
374
|
source: '《增删卜易》进神退神章、用神章',
|
|
374
375
|
status: 'variant',
|
|
375
|
-
note: '
|
|
376
|
+
note: '土之进退次序各家说法不完全一致,有以丑→辰→未→戌为进、也有只取辰戌丑未相对者;本插件按丑辰未戌成环处理,并用《增删卜易》卦例中「未土化戌土为进」「戌土化未土为退」对拍。喜忌分档的出处是《增删卜易》卷二·進神退神章第二十九:「所喜者宜於化進,所忌者宜化退神」;把「喜/忌」具体落到用神/忌神两档,是本插件的引申。',
|
|
376
377
|
},
|
|
377
378
|
|
|
378
379
|
// ── 梅花 / 六壬 / 奇门 / 塔罗 ───────────────────────────
|
|
@@ -170,10 +170,13 @@ export function buildAnswer(r, ask, ctx = {}) {
|
|
|
170
170
|
const ys = (r.frame && r.frame.yongshen) || {};
|
|
171
171
|
const favor = join(ys.favor);
|
|
172
172
|
const avoid = join(ys.avoid);
|
|
173
|
+
const neu = Array.isArray(ys.neutral) && ys.neutral.length
|
|
174
|
+
? `(其中${ys.neutral.map((n) => n.element).join('、')}在命局里几乎没有分量,算中性偏忌,不必刻意避)`
|
|
175
|
+
: '';
|
|
173
176
|
const ln = (r.liunian || [])[0];
|
|
174
177
|
const parts = [
|
|
175
178
|
head + `先说结论:你是${s(dm.stem)}${s(dm.element)}日主,命局${s(st.level, '待定')}` +
|
|
176
|
-
`${favor ? `,顺${favor}、忌${avoid}——往${favor}的方向安排事情会更省力` : ''}。`,
|
|
179
|
+
`${favor ? `,顺${favor}、忌${avoid}${neu}——往${favor}的方向安排事情会更省力` : ''}。`,
|
|
177
180
|
ln && ln.ganzhi
|
|
178
181
|
? `${s(ln.year)} 年是${ln.ganzhi}年(${s(ln.luck && ln.luck.tier, '平')}),这是「大环境」这一层。`
|
|
179
182
|
: '',
|
package/engine/interpret.js
CHANGED
|
@@ -171,6 +171,10 @@ function baziInterpret(r) {
|
|
|
171
171
|
const favor = Array.isArray(ys.favor) ? ys.favor : [];
|
|
172
172
|
const avoid = Array.isArray(ys.avoid) ? ys.avoid : [];
|
|
173
173
|
const disputed = Array.isArray(ys.disputed) ? ys.disputed : [];
|
|
174
|
+
const neutral = Array.isArray(ys.neutral) ? ys.neutral : [];
|
|
175
|
+
const neutralText = neutral.length
|
|
176
|
+
? `其中${neutral.map((n) => `${n.element}(${n.role})`).join('、')}全局仅 ${neutral.map((n) => n.weight).join('、')} 分,分量近零,按中性偏忌看;仍留在忌里,是因为行运走到这一行时照样按忌计。`
|
|
177
|
+
: '';
|
|
174
178
|
const primary = pick(frame, 'primaryName', '未取定');
|
|
175
179
|
const gender = pick(r.input, 'gender', '');
|
|
176
180
|
const isMale = gender === 'male';
|
|
@@ -338,7 +342,7 @@ function baziInterpret(r) {
|
|
|
338
342
|
|
|
339
343
|
const frameworkText = [
|
|
340
344
|
`**日主**:${dm.stem}${dm.element}(${dm.yinYang}${dm.element})${season ? `生于${season.branch}月,日主在月令「${season.word}」` : ''},命局${level}(${pick(st, 'score', '—')} 分)${stemP ? `——${stemP.image}之象` : ''}。`,
|
|
341
|
-
`**用神**:喜${join(favor) || '—'}(${join(ys.favorRoles || []) || '—'}),忌${join(avoid) || '—'}(${join(ys.avoidRoles || []) || '—'})。${frameToneOf(level, favorRolesByWeight)}`,
|
|
345
|
+
`**用神**:喜${join(favor) || '—'}(${join(ys.favorRoles || []) || '—'}),忌${join(avoid) || '—'}(${join(ys.avoidRoles || []) || '—'})。${neutral.length ? `(${join(neutral.map((n) => n.element))} 近零,按中性偏忌看)` : ''}${frameToneOf(level, favorRolesByWeight)}`,
|
|
342
346
|
`**格局**:${primary}(${pick(frame.primary, 'evidence', '')})${(Array.isArray(frame.geju) ? frame.geju : []).filter((g) => g.name && g.name !== primary).length
|
|
343
347
|
? `,另有${frame.geju.map((g) => g.name).filter((n) => n && n !== primary).join('、')}`
|
|
344
348
|
: ''}。`,
|
|
@@ -473,7 +477,7 @@ function baziInterpret(r) {
|
|
|
473
477
|
key: 'yongshen', label: '用神与忌神',
|
|
474
478
|
// detail 里通常已含调候说明,这里不再补一句,避免同一段出现两次「调候上…」
|
|
475
479
|
text: `喜用:${join(favor)}(对应十神:${join(ys.favorTenGods || ys.favorRoles || [])});忌:${join(avoid)}(对应十神:${join(ys.avoidTenGods || ys.avoidRoles || [])})。` +
|
|
476
|
-
`${pick(ys, 'detail', '')}`,
|
|
480
|
+
neutralText + `${pick(ys, 'detail', '')}`,
|
|
477
481
|
},
|
|
478
482
|
...(cli ? [{
|
|
479
483
|
key: 'climate', label: '寒暖燥湿',
|
|
@@ -515,7 +519,7 @@ function baziInterpret(r) {
|
|
|
515
519
|
// 一页读懂:报告顶部的五条结论(整体 / 事业 / 财富 / 感情 / 节奏)。
|
|
516
520
|
// 只做「摘要」,不引入新判断——全部取自下面已经算好的字段。
|
|
517
521
|
const outline = [
|
|
518
|
-
{ key: 'overall', label: '整体', text: `${level},喜${join(favor) || '—'}、忌${join(avoid) || '—'}` },
|
|
522
|
+
{ key: 'overall', label: '整体', text: `${level},喜${join(favor) || '—'}、忌${join(avoid) || '—'}${neutral.length ? `(${join(neutral.map((n) => n.element))} 近零·中性偏忌)` : ''}` },
|
|
519
523
|
{ key: 'career', label: '事业', text: `主格${primary},${topName}偏旺` },
|
|
520
524
|
{ key: 'wealth', label: '财富', text: `财星权重 ${groups['财'] ?? 0}${favor.includes('金') ? ',喜金助财' : ''}` },
|
|
521
525
|
{ key: 'love', label: '感情', text: `${spouseKey}星权重 ${groups[spouseKey] ?? 0},日支 ${pick(r.pillars?.day, 'branch', '—')}` },
|