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.
@@ -1,233 +1,233 @@
1
- // 奇门断语:分层输出「可复算事实 → 传统解释 → 关系 → 条件式倾向」。
2
- // 依据:「宫制其门不为迫,门制其宫门迫凶」——门迫严格限定同一宫内门五行克宫五行,
3
- // 宫克门是「宫制门(制)」,不是门迫。措辞一律条件式,禁止「必成/必败/绝对」。
4
- import { wuxingRelation, gatePalaceRelation } from './qimen.js';
5
-
6
- const GATE_MEAN = {
7
- 休门: '休为休息、蓄势,传统上主养精与谈判',
8
- 生门: '生为生发、财源,传统上主求财与谋事',
9
- 伤门: '伤为耗损、冲突,传统上主竞争与损耗',
10
- 杜门: '杜为闭塞、隐藏,传统上主保密与研究',
11
- 景门: '景为文书、声名,传统上主宣传与考试',
12
- 死门: '死为终结、收束,传统上主了断与送旧',
13
- 惊门: '惊为惊动、口舌,传统上主争辩与追讨',
14
- 开门: '开为开张、通达,传统上主上任与开拓',
15
- };
16
- const STAR_MEAN = {
17
- 天蓬: '天蓬主暗昧、胆大', 天任: '天任主厚稳、经营', 天冲: '天冲主快速、行动',
18
- 天辅: '天辅主文教、辅助', 天英: '天英主显扬、热烈', 天芮: '天芮主病患、纠缠',
19
- 天柱: '天柱主口舌、阻隔', 天心: '天心主谋略、医术', 天禽: '天禽主中正、协调', 禽芮: '禽芮主中正兼病气',
20
- };
21
- const GOD_MEAN = {
22
- 值符: '值符为首领,主主导权与贵人', 腾蛇: '腾蛇主虚惊、反复', 太阴: '太阴主暗助、私密',
23
- 六合: '六合主和合、媒介', 白虎: '白虎主刚烈、伤病', 玄武: '玄武主暗昧、失脱',
24
- 九地: '九地主沉稳、守成', 九天: '九天主高远、扬动',
25
- };
26
- const YONG_SHEN = {
27
- general: { label: '综合', primary: ['开门'], secondary: ['生门'], note: '综合以开、生两门为候选用神' },
28
- wealth: { label: '财运', primary: ['生门'], secondary: ['开门'], note: '求财以生门为主,开门为辅' },
29
- career: { label: '事业', primary: ['开门'], secondary: ['值符'], note: '事业以开门为主,值符(主导权)为辅' },
30
- love: { label: '感情', primary: ['休门'], secondary: ['六合'], note: '感情以休门为主,六合(和合)为辅' },
31
- study: { label: '学业', primary: ['景门'], secondary: ['天辅'], note: '学业以景门为主,天辅(文教)为辅' },
32
- health: { label: '健康', primary: ['天芮'], secondary: ['死门'], note: '问病以天芮为主,死门为辅;只作传统取象,不作诊断' },
33
- travel: { label: '出行', primary: ['九天'], secondary: ['驿马'], note: '出行以九天为主,兼看驿马' },
34
- };
35
-
36
- /** 天盘干与宫的落宫关系统计:干克宫 3 宫(辛)… */
37
- function stemRelationLine(r) {
38
- const groups = new Map();
39
- for (const p of r.palaces || []) {
40
- const rel = p.stemRelation || null;
41
- if (!rel || rel.type === 'unknown' || !p.tianPan) continue;
42
- if (!groups.has(rel.type)) groups.set(rel.type, []);
43
- groups.get(rel.type).push(`${p.palace}宫${p.tianPan}`);
44
- }
45
- const order = ['干克宫', '宫克干', '干生宫', '宫生干', '比和'];
46
- return order.filter((k) => groups.has(k)).map((k) => `${k} ${groups.get(k).join('、')}`).join(';') || '—';
47
- }
48
-
49
- const REL_TEXT = {
50
- 生: '主体力量流向环境或趋势',
51
- 克: '主体对环境或趋势构成压力、有改造意图',
52
- 比和: '两者取向相近、力量相若',
53
- 被生: '环境或趋势为主体提供支持条件',
54
- 被克: '环境或趋势对主体构成约束',
55
- unknown: '五行缺失,关系未定',
56
- };
57
-
58
- const findPalace = (r, key) => r.palaces.find((p) => p.star === key || p.gate === key || p.god === key || p.palace === key) || null;
59
- const cell = (p) => `${p.palace}宫(${p.star}·${p.gate}·${p.god})`;
60
-
61
- /** 按询问方向取用神及其落宫;解读与推导链共用这一张表,避免两处各写一份 */
62
- export function qimenYongshen(r, direction) {
63
- const dir = YONG_SHEN[direction] ? direction : 'general';
64
- const ys = YONG_SHEN[dir];
65
- return {
66
- direction: dir,
67
- label: ys.label,
68
- note: ys.note,
69
- rows: [...ys.primary, ...ys.secondary].map((key) => ({ key, palace: findPalace(r, key) })),
70
- };
71
- }
72
-
73
- export function interpretQimen(r, opts = {}) {
74
- if (!r || r.system !== 'qimen') return null;
75
- const ysInfo = qimenYongshen(r, opts.direction);
76
- const dir = ysInfo.direction;
77
- const ys = YONG_SHEN[dir];
78
- const sections = [];
79
- const unresolved = [];
80
-
81
- // ① 事实层(全部可直接复算)
82
- sections.push({
83
- key: 'facts',
84
- label: '排盘事实',
85
- text: `${r.ju};节气 ${r.jieqi}(${r.jieqiTime});${r.siZhu.year}年 ${r.siZhu.month}月 ${r.siZhu.day}日 ${r.siZhu.time}时;`
86
- + `值符 ${r.zhiFu.star} 落 ${r.zhiFu.gong} 宫,值使 ${r.zhiShi.gate} 落 ${r.zhiShi.gong} 宫;`
87
- + `旬首 ${r.xunshou};空亡 ${r.kongWang.join('') || '—'};驿马 ${r.ma.zhi || '—'}。`
88
- + (r.juMethodNote ? `取局口径:${r.juMethodNote}。` : ''),
89
- });
90
-
91
- // ② 单宫解释
92
- const zhiFuP = findPalace(r, r.zhiFu.gong);
93
- const zhiShiP = findPalace(r, r.zhiShi.gong);
94
- if (zhiFuP) {
95
- sections.push({
96
- key: 'zhifu',
97
- label: '值符落宫(单宫)',
98
- text: `值符 ${r.zhiFu.star} 在 ${cell(zhiFuP)}。事实:宫属${zhiFuP.palaceElement},门属${zhiFuP.gateElement || '—'},星属${zhiFuP.starElement || '—'}。`
99
- + `传统解释:${STAR_MEAN[zhiFuP.star] || ''};${GATE_MEAN[zhiFuP.gate] || ''};${GOD_MEAN[zhiFuP.god] || ''}。`
100
- + `此宫可读作当下较易发力的位置,但不等于事情即此定向。`,
101
- });
102
- }
103
- if (zhiShiP) {
104
- sections.push({
105
- key: 'zhishi',
106
- label: '值使落宫(单宫)',
107
- text: `值使 ${r.zhiShi.gate} 在 ${cell(zhiShiP)}。传统解释:${GATE_MEAN[zhiShiP.gate] || ''}。值使所落之宫常被读作事情推进的口子。`,
108
- });
109
- }
110
-
111
- // ③ 用神候选
112
- const yongList = ysInfo.rows.filter((x) => x.palace);
113
- if (!yongList.length) unresolved.push(`${ys.label}的用神未上盘`);
114
- if (yongList.length > 1) unresolved.push(`用神有 ${yongList.length} 个候选(${yongList.map((x) => x.key).join('、')})`);
115
- sections.push({
116
- key: 'yongshen',
117
- label: `用神候选(${ys.label})`,
118
- text: `${ys.note}。` + (yongList.length
119
- ? yongList.map((x) => `${x.key} → ${cell(x.palace)}`).join(';') + '。'
120
- : '本盘未见对应符号,暂以值符落宫参照,属未决项。'),
121
- });
122
-
123
- // ④ 两宫关系(用神宫 × 值符宫)
124
- const primary = yongList[0] || null;
125
- if (primary && zhiFuP) {
126
- if (primary.palace.palace === zhiFuP.palace) {
127
- sections.push({
128
- key: 'relation',
129
- label: '用神宫 × 值符宫',
130
- text: `用神与值符同处 ${zhiFuP.palace} 宫(同宫)——关系并不因此消失,需看该宫门星神与旺衰;`
131
- + `该宫门宫关系为「${(zhiFuP.gateRelation || gatePalaceRelation(zhiFuP.gate, zhiFuP.palace)).type}」。`,
132
- });
133
- } else {
134
- const rel = wuxingRelation(primary.palace.palaceElement, zhiFuP.palaceElement);
135
- sections.push({
136
- key: 'relation',
137
- label: '用神宫 × 值符宫',
138
- text: `用神宫(${primary.palace.palace},${primary.palace.palaceElement})对值符宫(${zhiFuP.palace},${zhiFuP.palaceElement})为「${rel}」:${REL_TEXT[rel] || '关系未定'}。`
139
- + `这是落宫五行层面的关系;是否占优还要看门、月令与所问之事。`,
140
- });
141
- }
142
- }
143
-
144
- // ⑤ 宫位条件:门迫严格同宫,宫制门单列
145
- const forced = [];
146
- const controlled = [];
147
- for (const p of r.palaces) {
148
- const rel = p.gateRelation || gatePalaceRelation(p.gate, p.palace);
149
- if (rel.type === '门迫') forced.push(`${p.palace}宫(${p.gate}${rel.gate}克宫${rel.palace})`);
150
- else if (rel.type === '宫制门') controlled.push(`${p.palace}宫(宫${rel.palace}克${p.gate}${rel.gate})`);
151
- }
152
- const kongCells = r.palaces.filter((p) => p.kong).map((p) => `${p.palace}宫`);
153
- const jiXing = (r.conditions && r.conditions.jiXing) || [];
154
- const ruMu = (r.conditions && r.conditions.ruMu) || [];
155
- const liuYiRuMu = (r.conditions && r.conditions.liuYiRuMu) || [];
156
- sections.push({
157
- key: 'conditions',
158
- label: '宫位条件',
159
- text: `门迫(同宫内门克宫):${forced.length ? forced.join('、') : '本盘无'};`
160
- + `宫制门(宫克门,属「制」不为迫):${controlled.length ? controlled.join('、') : '无'}。`
161
- + `击刑(天盘六仪落刑宫):${jiXing.length ? jiXing.map((x) => `${x.palace}宫${x.stem}(${x.basis})`).join('、') : '本盘无'};`
162
- + `三奇入墓(天盘乙丙丁落墓宫):${ruMu.length ? ruMu.map((x) => `${x.palace}宫${x.stem}(${x.basis})`).join('、') : '本盘无'};`
163
- + `六仪入墓(天盘戊己庚辛壬癸落墓宫):${liuYiRuMu.length ? liuYiRuMu.map((x) => `${x.palace}宫${x.stem}(${x.basis})`).join('、') : '本盘无'}。`
164
- + (kongCells.length ? `空亡:${kongCells.join('、')}——落空之宫事多不实。` : '无落空之宫。')
165
- + `这些条件都只作宫位条件:门迫、击刑、入墓不自动等同于用神受制,取象时看它们落在哪个符号上。`,
166
- });
167
-
168
- // ⑤a 十干克应:天盘干加地盘干的 100 组成象,逐宫列出
169
- const gyCells = [...r.palaces, r.centerPalace].filter((p) => p && p.ganYing);
170
- sections.push({
171
- key: 'ganying',
172
- label: '十干克应',
173
- text: (gyCells.length
174
- ? gyCells.map((p) => `${p.palace}宫 天${p.ganYing.tian}加地${p.ganYing.di}「${p.ganYing.name}」:${p.ganYing.text}`).join(';')
175
- : '本盘没有可判的天盘干加地盘干。')
176
- + '十干克应只作取象与读盘线索,与门宫、干宫生克并列,不自动折吉凶;同一组落在不同门星神下,轻重也不同。',
177
- });
178
-
179
- // ⑤b 月令旺衰:门、星、天盘干按月支五行判五态(与门迫这类宫位关系分开)
180
- const mo = r.month || null;
181
- const st = r.states || null;
182
- if (mo && st) {
183
- const order = ['旺', '相', '休', '囚', '死'];
184
- const line = (g) => order.filter((k) => g && Array.isArray(g[k]) && g[k].length)
185
- .map((k) => `${k} ${g[k].join('、')}`).join(';') || '—';
186
- sections.push({
187
- key: 'states',
188
- label: '月令旺衰',
189
- text: `月令 ${mo.branch}(${mo.element}):`
190
- + `门 ${line(st.gate)}。星 ${line(st.star)}。天盘干 ${line(st.stem)}。`
191
- + `旺为同月令之气,相为月令所生,休为生月令,囚为克月令,死为月令所克。`
192
- + `干宫的落宫关系另算:${stemRelationLine(r)}。`
193
- + `这一层只说明门、星、干自身力量强弱,不合吉凶:门旺而宫克门,仍受宫制;星旺而落宫死地,也难全其用。`,
194
- });
195
- }
196
-
197
- // ⑥ 条件式倾向
198
- if (unresolved.length) {
199
- sections.push({
200
- key: 'tendency',
201
- label: '最终倾向',
202
- text: `暂不给单一倾向。未决项:${unresolved.join(';')}。先把用神定下来,再谈顺逆。`,
203
- });
204
- } else {
205
- const rel = wuxingRelation(primary.palace.palaceElement, zhiFuP.palaceElement);
206
- const tone = rel === '被生' || rel === '生' ? '偏向顺' : rel === '被克' ? '偏向滞' : '中性';
207
- sections.push({
208
- key: 'tendency',
209
- label: '最终倾向',
210
- text: `在当前输入、规则集与所问之事下:若以「${primary.key}」为用神,用神宫对值符宫为「${rel}」,整体${tone};`
211
- + `若${ys.label}实际取另一个候选,或时间范围不同,解读边界随之变化。干宫生克与十干克应已并列取象,仍只作落宫条件与读盘线索,不折吉凶。`,
212
- });
213
- }
214
-
215
- // ⑦ 复核清单
216
- sections.push({
217
- key: 'checklist',
218
- label: '复核清单',
219
- text: '建议人工核对:①出生时间与真太阳时是否一致;②取局口径(拆补/置闰/超接)是否与所用流派一致;'
220
- + '③用神是否取对;④空亡宫是否影响关键符号;⑤若结论与现实直觉冲突,先查输入与规则。',
221
- });
222
-
223
- return {
224
- system: 'qimen',
225
- moduleType: 'divination',
226
- question: opts.question || '',
227
- direction: dir,
228
- sections,
229
- unresolved,
230
- ruleset: { juMethod: r.juMethod, schema: 'interpret/2' },
231
- disclaimer: '奇门属传统术数,用于整理思路与排序选项;不构成对现实的确定性预测,重要决策请以事实与专业意见为准。',
232
- };
233
- }
1
+ // 奇门断语:分层输出「可复算事实 → 传统解释 → 关系 → 条件式倾向」。
2
+ // 依据:「宫制其门不为迫,门制其宫门迫凶」——门迫严格限定同一宫内门五行克宫五行,
3
+ // 宫克门是「宫制门(制)」,不是门迫。措辞一律条件式,禁止「必成/必败/绝对」。
4
+ import { wuxingRelation, gatePalaceRelation } from './qimen.js';
5
+
6
+ const GATE_MEAN = {
7
+ 休门: '休为休息、蓄势,传统上主养精与谈判',
8
+ 生门: '生为生发、财源,传统上主求财与谋事',
9
+ 伤门: '伤为耗损、冲突,传统上主竞争与损耗',
10
+ 杜门: '杜为闭塞、隐藏,传统上主保密与研究',
11
+ 景门: '景为文书、声名,传统上主宣传与考试',
12
+ 死门: '死为终结、收束,传统上主了断与送旧',
13
+ 惊门: '惊为惊动、口舌,传统上主争辩与追讨',
14
+ 开门: '开为开张、通达,传统上主上任与开拓',
15
+ };
16
+ const STAR_MEAN = {
17
+ 天蓬: '天蓬主暗昧、胆大', 天任: '天任主厚稳、经营', 天冲: '天冲主快速、行动',
18
+ 天辅: '天辅主文教、辅助', 天英: '天英主显扬、热烈', 天芮: '天芮主病患、纠缠',
19
+ 天柱: '天柱主口舌、阻隔', 天心: '天心主谋略、医术', 天禽: '天禽主中正、协调', 禽芮: '禽芮主中正兼病气',
20
+ };
21
+ const GOD_MEAN = {
22
+ 值符: '值符为首领,主主导权与贵人', 腾蛇: '腾蛇主虚惊、反复', 太阴: '太阴主暗助、私密',
23
+ 六合: '六合主和合、媒介', 白虎: '白虎主刚烈、伤病', 玄武: '玄武主暗昧、失脱',
24
+ 九地: '九地主沉稳、守成', 九天: '九天主高远、扬动',
25
+ };
26
+ const YONG_SHEN = {
27
+ general: { label: '综合', primary: ['开门'], secondary: ['生门'], note: '综合以开、生两门为候选用神' },
28
+ wealth: { label: '财运', primary: ['生门'], secondary: ['开门'], note: '求财以生门为主,开门为辅' },
29
+ career: { label: '事业', primary: ['开门'], secondary: ['值符'], note: '事业以开门为主,值符(主导权)为辅' },
30
+ love: { label: '感情', primary: ['休门'], secondary: ['六合'], note: '感情以休门为主,六合(和合)为辅' },
31
+ study: { label: '学业', primary: ['景门'], secondary: ['天辅'], note: '学业以景门为主,天辅(文教)为辅' },
32
+ health: { label: '健康', primary: ['天芮'], secondary: ['死门'], note: '问病以天芮为主,死门为辅;只作传统取象,不作诊断' },
33
+ travel: { label: '出行', primary: ['九天'], secondary: ['驿马'], note: '出行以九天为主,兼看驿马' },
34
+ };
35
+
36
+ /** 天盘干与宫的落宫关系统计:干克宫 3 宫(辛)… */
37
+ function stemRelationLine(r) {
38
+ const groups = new Map();
39
+ for (const p of r.palaces || []) {
40
+ const rel = p.stemRelation || null;
41
+ if (!rel || rel.type === 'unknown' || !p.tianPan) continue;
42
+ if (!groups.has(rel.type)) groups.set(rel.type, []);
43
+ groups.get(rel.type).push(`${p.palace}宫${p.tianPan}`);
44
+ }
45
+ const order = ['干克宫', '宫克干', '干生宫', '宫生干', '比和'];
46
+ return order.filter((k) => groups.has(k)).map((k) => `${k} ${groups.get(k).join('、')}`).join(';') || '—';
47
+ }
48
+
49
+ const REL_TEXT = {
50
+ 生: '主体力量流向环境或趋势',
51
+ 克: '主体对环境或趋势构成压力、有改造意图',
52
+ 比和: '两者取向相近、力量相若',
53
+ 被生: '环境或趋势为主体提供支持条件',
54
+ 被克: '环境或趋势对主体构成约束',
55
+ unknown: '五行缺失,关系未定',
56
+ };
57
+
58
+ const findPalace = (r, key) => r.palaces.find((p) => p.star === key || p.gate === key || p.god === key || p.palace === key) || null;
59
+ const cell = (p) => `${p.palace}宫(${p.star}·${p.gate}·${p.god})`;
60
+
61
+ /** 按询问方向取用神及其落宫;解读与推导链共用这一张表,避免两处各写一份 */
62
+ export function qimenYongshen(r, direction) {
63
+ const dir = YONG_SHEN[direction] ? direction : 'general';
64
+ const ys = YONG_SHEN[dir];
65
+ return {
66
+ direction: dir,
67
+ label: ys.label,
68
+ note: ys.note,
69
+ rows: [...ys.primary, ...ys.secondary].map((key) => ({ key, palace: findPalace(r, key) })),
70
+ };
71
+ }
72
+
73
+ export function interpretQimen(r, opts = {}) {
74
+ if (!r || r.system !== 'qimen') return null;
75
+ const ysInfo = qimenYongshen(r, opts.direction);
76
+ const dir = ysInfo.direction;
77
+ const ys = YONG_SHEN[dir];
78
+ const sections = [];
79
+ const unresolved = [];
80
+
81
+ // ① 事实层(全部可直接复算)
82
+ sections.push({
83
+ key: 'facts',
84
+ label: '排盘事实',
85
+ text: `${r.ju};节气 ${r.jieqi}(${r.jieqiTime});${r.siZhu.year}年 ${r.siZhu.month}月 ${r.siZhu.day}日 ${r.siZhu.time}时;`
86
+ + `值符 ${r.zhiFu.star} 落 ${r.zhiFu.gong} 宫,值使 ${r.zhiShi.gate} 落 ${r.zhiShi.gong} 宫;`
87
+ + `旬首 ${r.xunshou};空亡 ${r.kongWang.join('') || '—'};驿马 ${r.ma.zhi || '—'}。`
88
+ + (r.juMethodNote ? `取局口径:${r.juMethodNote}。` : ''),
89
+ });
90
+
91
+ // ② 单宫解释
92
+ const zhiFuP = findPalace(r, r.zhiFu.gong);
93
+ const zhiShiP = findPalace(r, r.zhiShi.gong);
94
+ if (zhiFuP) {
95
+ sections.push({
96
+ key: 'zhifu',
97
+ label: '值符落宫(单宫)',
98
+ text: `值符 ${r.zhiFu.star} 在 ${cell(zhiFuP)}。事实:宫属${zhiFuP.palaceElement},门属${zhiFuP.gateElement || '—'},星属${zhiFuP.starElement || '—'}。`
99
+ + `传统解释:${STAR_MEAN[zhiFuP.star] || ''};${GATE_MEAN[zhiFuP.gate] || ''};${GOD_MEAN[zhiFuP.god] || ''}。`
100
+ + `此宫可读作当下较易发力的位置,但不等于事情即此定向。`,
101
+ });
102
+ }
103
+ if (zhiShiP) {
104
+ sections.push({
105
+ key: 'zhishi',
106
+ label: '值使落宫(单宫)',
107
+ text: `值使 ${r.zhiShi.gate} 在 ${cell(zhiShiP)}。传统解释:${GATE_MEAN[zhiShiP.gate] || ''}。值使所落之宫常被读作事情推进的口子。`,
108
+ });
109
+ }
110
+
111
+ // ③ 用神候选
112
+ const yongList = ysInfo.rows.filter((x) => x.palace);
113
+ if (!yongList.length) unresolved.push(`${ys.label}的用神未上盘`);
114
+ if (yongList.length > 1) unresolved.push(`用神有 ${yongList.length} 个候选(${yongList.map((x) => x.key).join('、')})`);
115
+ sections.push({
116
+ key: 'yongshen',
117
+ label: `用神候选(${ys.label})`,
118
+ text: `${ys.note}。` + (yongList.length
119
+ ? yongList.map((x) => `${x.key} → ${cell(x.palace)}`).join(';') + '。'
120
+ : '本盘未见对应符号,暂以值符落宫参照,属未决项。'),
121
+ });
122
+
123
+ // ④ 两宫关系(用神宫 × 值符宫)
124
+ const primary = yongList[0] || null;
125
+ if (primary && zhiFuP) {
126
+ if (primary.palace.palace === zhiFuP.palace) {
127
+ sections.push({
128
+ key: 'relation',
129
+ label: '用神宫 × 值符宫',
130
+ text: `用神与值符同处 ${zhiFuP.palace} 宫(同宫)——关系并不因此消失,需看该宫门星神与旺衰;`
131
+ + `该宫门宫关系为「${(zhiFuP.gateRelation || gatePalaceRelation(zhiFuP.gate, zhiFuP.palace)).type}」。`,
132
+ });
133
+ } else {
134
+ const rel = wuxingRelation(primary.palace.palaceElement, zhiFuP.palaceElement);
135
+ sections.push({
136
+ key: 'relation',
137
+ label: '用神宫 × 值符宫',
138
+ text: `用神宫(${primary.palace.palace},${primary.palace.palaceElement})对值符宫(${zhiFuP.palace},${zhiFuP.palaceElement})为「${rel}」:${REL_TEXT[rel] || '关系未定'}。`
139
+ + `这是落宫五行层面的关系;是否占优还要看门、月令与所问之事。`,
140
+ });
141
+ }
142
+ }
143
+
144
+ // ⑤ 宫位条件:门迫严格同宫,宫制门单列
145
+ const forced = [];
146
+ const controlled = [];
147
+ for (const p of r.palaces) {
148
+ const rel = p.gateRelation || gatePalaceRelation(p.gate, p.palace);
149
+ if (rel.type === '门迫') forced.push(`${p.palace}宫(${p.gate}${rel.gate}克宫${rel.palace})`);
150
+ else if (rel.type === '宫制门') controlled.push(`${p.palace}宫(宫${rel.palace}克${p.gate}${rel.gate})`);
151
+ }
152
+ const kongCells = r.palaces.filter((p) => p.kong).map((p) => `${p.palace}宫`);
153
+ const jiXing = (r.conditions && r.conditions.jiXing) || [];
154
+ const ruMu = (r.conditions && r.conditions.ruMu) || [];
155
+ const liuYiRuMu = (r.conditions && r.conditions.liuYiRuMu) || [];
156
+ sections.push({
157
+ key: 'conditions',
158
+ label: '宫位条件',
159
+ text: `门迫(同宫内门克宫):${forced.length ? forced.join('、') : '本盘无'};`
160
+ + `宫制门(宫克门,属「制」不为迫):${controlled.length ? controlled.join('、') : '无'}。`
161
+ + `击刑(天盘六仪落刑宫):${jiXing.length ? jiXing.map((x) => `${x.palace}宫${x.stem}(${x.basis})`).join('、') : '本盘无'};`
162
+ + `三奇入墓(天盘乙丙丁落墓宫):${ruMu.length ? ruMu.map((x) => `${x.palace}宫${x.stem}(${x.basis})`).join('、') : '本盘无'};`
163
+ + `六仪入墓(天盘戊己庚辛壬癸落墓宫):${liuYiRuMu.length ? liuYiRuMu.map((x) => `${x.palace}宫${x.stem}(${x.basis})`).join('、') : '本盘无'}。`
164
+ + (kongCells.length ? `空亡:${kongCells.join('、')}——落空之宫事多不实。` : '无落空之宫。')
165
+ + `这些条件都只作宫位条件:门迫、击刑、入墓不自动等同于用神受制,取象时看它们落在哪个符号上。`,
166
+ });
167
+
168
+ // ⑤a 十干克应:天盘干加地盘干的 100 组成象,逐宫列出
169
+ const gyCells = [...r.palaces, r.centerPalace].filter((p) => p && p.ganYing);
170
+ sections.push({
171
+ key: 'ganying',
172
+ label: '十干克应',
173
+ text: (gyCells.length
174
+ ? gyCells.map((p) => `${p.palace}宫 天${p.ganYing.tian}加地${p.ganYing.di}「${p.ganYing.name}」:${p.ganYing.text}`).join(';')
175
+ : '本盘没有可判的天盘干加地盘干。')
176
+ + '十干克应只作取象与读盘线索,与门宫、干宫生克并列,不自动折吉凶;同一组落在不同门星神下,轻重也不同。',
177
+ });
178
+
179
+ // ⑤b 月令旺衰:门、星、天盘干按月支五行判五态(与门迫这类宫位关系分开)
180
+ const mo = r.month || null;
181
+ const st = r.states || null;
182
+ if (mo && st) {
183
+ const order = ['旺', '相', '休', '囚', '死'];
184
+ const line = (g) => order.filter((k) => g && Array.isArray(g[k]) && g[k].length)
185
+ .map((k) => `${k} ${g[k].join('、')}`).join(';') || '—';
186
+ sections.push({
187
+ key: 'states',
188
+ label: '月令旺衰',
189
+ text: `月令 ${mo.branch}(${mo.element}):`
190
+ + `门 ${line(st.gate)}。星 ${line(st.star)}。天盘干 ${line(st.stem)}。`
191
+ + `旺为同月令之气,相为月令所生,休为生月令,囚为克月令,死为月令所克。`
192
+ + `干宫的落宫关系另算:${stemRelationLine(r)}。`
193
+ + `这一层只说明门、星、干自身力量强弱,不合吉凶:门旺而宫克门,仍受宫制;星旺而落宫死地,也难全其用。`,
194
+ });
195
+ }
196
+
197
+ // ⑥ 条件式倾向
198
+ if (unresolved.length) {
199
+ sections.push({
200
+ key: 'tendency',
201
+ label: '最终倾向',
202
+ text: `暂不给单一倾向。未决项:${unresolved.join(';')}。先把用神定下来,再谈顺逆。`,
203
+ });
204
+ } else {
205
+ const rel = wuxingRelation(primary.palace.palaceElement, zhiFuP.palaceElement);
206
+ const tone = rel === '被生' || rel === '生' ? '偏向顺' : rel === '被克' ? '偏向滞' : '中性';
207
+ sections.push({
208
+ key: 'tendency',
209
+ label: '最终倾向',
210
+ text: `在当前输入、规则集与所问之事下:若以「${primary.key}」为用神,用神宫对值符宫为「${rel}」,整体${tone};`
211
+ + `若${ys.label}实际取另一个候选,或时间范围不同,解读边界随之变化。干宫生克与十干克应已并列取象,仍只作落宫条件与读盘线索,不折吉凶。`,
212
+ });
213
+ }
214
+
215
+ // ⑦ 复核清单
216
+ sections.push({
217
+ key: 'checklist',
218
+ label: '复核清单',
219
+ text: '建议人工核对:①出生时间与真太阳时是否一致;②取局口径(拆补/置闰/超接)是否与所用流派一致;'
220
+ + '③用神是否取对;④空亡宫是否影响关键符号;⑤若结论与现实直觉冲突,先查输入与规则。',
221
+ });
222
+
223
+ return {
224
+ system: 'qimen',
225
+ moduleType: 'divination',
226
+ question: opts.question || '',
227
+ direction: dir,
228
+ sections,
229
+ unresolved,
230
+ ruleset: { juMethod: r.juMethod, schema: 'interpret/2' },
231
+ disclaimer: '奇门属传统术数,用于整理思路与排序选项;不构成对现实的确定性预测,重要决策请以事实与专业意见为准。',
232
+ };
233
+ }
@@ -0,0 +1,162 @@
1
+ // C2 对话→参数回填:把「换成紫微看 2030 年事业」这类一句话改参,翻成具体的参数补丁。
2
+ //
3
+ // 只做「明确的改参句式」:识别不到就原样返回,绝不猜——猜错会把用户的盘悄悄换成另一张。
4
+ // 所以每条规则都要求有切换词(换成 / 改成 / 看 / 用 / 按…),单纯提一句「紫微」不算。
5
+ // 出生时间、经度这类需要精确值的字段不在这里改(一句话改不出分秒),只提示改传原始参数。
6
+
7
+ const SYSTEMS = [
8
+ { key: 'ziwei', label: '紫微', re: /紫微|斗数/ },
9
+ { key: 'bazi', label: '八字', re: /八字|四柱/ },
10
+ { key: 'liuyao', label: '六爻', re: /六爻|摇卦/ },
11
+ { key: 'qimen', label: '奇门', re: /奇门/ },
12
+ { key: 'daliuren', label: '大六壬', re: /大六壬|六壬/ },
13
+ { key: 'tarot', label: '塔罗', re: /塔罗|抽牌/ },
14
+ { key: 'meihua', label: '梅花', re: /梅花/ },
15
+ { key: 'hepan', label: '合盘', re: /合盘|合婚/ },
16
+ { key: 'almanac', label: '黄历', re: /黄历|老黄历/ },
17
+ { key: 'zeri', label: '择日', re: /择日|挑日子/ },
18
+ { key: 'fengshui', label: '风水', re: /风水/ },
19
+ { key: 'name', label: '起名', re: /起名|取名/ },
20
+ { key: 'chenggu', label: '称骨', re: /称骨/ },
21
+ { key: 'xiaoliuren', label: '小六壬', re: /小六壬/ },
22
+ { key: 'star', label: '星座', re: /星座/ },
23
+ { key: 'numerology', label: '生命数字', re: /生命数字|生命灵数/ },
24
+ { key: 'mbti', label: 'MBTI', re: /mbti|人格测试|十六型/i },
25
+ { key: 'trend', label: '人生 K 线', re: /k\s*线|人生曲线/i },
26
+ { key: 'convert', label: '公农历互转', re: /农历转公历|公历转农历|公农历/ },
27
+ ];
28
+
29
+ const DIRECTIONS = [
30
+ { key: 'love', label: '感情', re: /感情|婚姻|恋爱|对象|夫妻/ },
31
+ { key: 'wealth', label: '财运', re: /财运|财富|赚钱|收入|破财/ },
32
+ { key: 'career', label: '事业', re: /事业|工作|升职|跳槽/ },
33
+ { key: 'health', label: '健康', re: /健康|身体|疾病|病/ },
34
+ { key: 'study', label: '学业', re: /学业|考试|考研|升学|读书/ },
35
+ { key: 'travel', label: '出行', re: /出行|搬家|迁移|旅行|外地/ },
36
+ ];
37
+
38
+ const SWITCH = /换成|改成|改为|换到|改看|再看|再看一下|换一套|排一?张|用|按|看/;
39
+
40
+ const cleanPlace = (s) => String(s || '')
41
+ .replace(/(出生|出生地|所在地|人)$/, '')
42
+ .replace(/[的了].*$/, '')
43
+ .trim();
44
+
45
+ /**
46
+ * 一句话改参 → 参数补丁。
47
+ * @returns {{text:string, patch:object, labels:{key:string,label:string,value:any,display:string}[], ignored:string[]}}
48
+ */
49
+ export function parseRevision(text) {
50
+ const src = String(text == null ? '' : text).trim();
51
+ const patch = {};
52
+ const labels = [];
53
+ const ignored = [];
54
+ if (!src) return { text: '', patch, labels, ignored };
55
+
56
+ // ① 换体系:必须有切换词,避免把「紫微里怎么说」当成要换盘
57
+ if (SWITCH.test(src)) {
58
+ for (const s of SYSTEMS) {
59
+ if (s.re.test(src)) {
60
+ patch.system = s.key;
61
+ labels.push({ key: 'system', label: '体系', value: s.key, display: s.label });
62
+ break;
63
+ }
64
+ }
65
+ }
66
+
67
+ // ② 性别
68
+ if (/女命|女性|换成女|改成女|女盘/.test(src)) {
69
+ patch.gender = 'female';
70
+ labels.push({ key: 'gender', label: '性别', value: 'female', display: '女' });
71
+ } else if (/男命|男性|换成男|改成男|男盘/.test(src)) {
72
+ patch.gender = 'male';
73
+ labels.push({ key: 'gender', label: '性别', value: 'male', display: '男' });
74
+ }
75
+
76
+ // ③ 晚子时:只认「晚子时」出现在改写句里
77
+ if (/晚子时/.test(src)) {
78
+ if (/不换日|不换天|算当日|归当日|按当日|当天/.test(src)) {
79
+ patch.lateZi = false;
80
+ labels.push({ key: 'lateZi', label: '晚子时', value: false, display: '23:00 后仍算当日' });
81
+ } else if (/换日|算次日|归次日|按次日|第二天|次日/.test(src)) {
82
+ patch.lateZi = true;
83
+ labels.push({ key: 'lateZi', label: '晚子时', value: true, display: '23:00 后算次日' });
84
+ }
85
+ }
86
+
87
+ // ④ 真太阳时
88
+ if (/真太阳时/.test(src)) {
89
+ if (/不用|不要|关闭|关掉|取消|不算/.test(src)) {
90
+ patch.trueSolar = false;
91
+ labels.push({ key: 'trueSolar', label: '真太阳时', value: false, display: '用东八区平太阳时' });
92
+ } else {
93
+ patch.trueSolar = true;
94
+ labels.push({ key: 'trueSolar', label: '真太阳时', value: true, display: '按出生地经度校正' });
95
+ }
96
+ }
97
+
98
+ // ⑤ 夏令时
99
+ if (/夏令时/.test(src)) {
100
+ if (/不用|不要|关闭|关掉|取消|不校正/.test(src)) {
101
+ patch.dst = false;
102
+ labels.push({ key: 'dst', label: '夏令时', value: false, display: '不自动校正 1986–1991 夏令时' });
103
+ } else {
104
+ patch.dst = true;
105
+ labels.push({ key: 'dst', label: '夏令时', value: true, display: '自动校正 1986–1991 夏令时' });
106
+ }
107
+ }
108
+
109
+ // ⑥ 出生地:只认「出生在 X」「出生地改成 X」这两种明确句式
110
+ const place = src.match(/出生在\s*([\u4e00-\u9fa5]{2,12})/)
111
+ || src.match(/出生地(?:改成|改为|换成|换到|是|为)?\s*([\u4e00-\u9fa5]{2,12})/)
112
+ || src.match(/改到\s*([\u4e00-\u9fa5]{2,12})\s*出生/);
113
+ if (place) {
114
+ const name = cleanPlace(place[1]);
115
+ if (name.length >= 2) {
116
+ patch.address = name;
117
+ labels.push({ key: 'address', label: '出生地', value: name, display: name });
118
+ }
119
+ }
120
+
121
+ // ⑦ 看哪一年:只认「看 / 查 / 问 + 年份」,避免把「1990 年出生」当成流年
122
+ const year = src.match(/(?:看|查|问|到|到了|临近)\s*((?:19|20)\d{2})\s*年/)
123
+ || src.match(/((?:19|20)\d{2})\s*年(?:的)?(?:运势|怎么样|如何|会怎样|流年)/);
124
+ if (year) {
125
+ const y = Number(year[1]);
126
+ patch.asOf = `${y}-01-01T00:00`;
127
+ labels.push({ key: 'asOf', label: '流年基准', value: patch.asOf, display: `${y} 年` });
128
+ } else if (/(出生|生年)/.test(src) && /(19|20)\d{2}\s*年/.test(src)) {
129
+ ignored.push('出生年份没改:一句话改不出日与时辰,请直接传 datetime(如 1993-04-08T06:20)');
130
+ }
131
+
132
+ // ⑧ 询问方向
133
+ for (const d of DIRECTIONS) {
134
+ if (d.re.test(src)) {
135
+ patch.direction = d.key;
136
+ labels.push({ key: 'direction', label: '询问方向', value: d.key, display: d.label });
137
+ break;
138
+ }
139
+ }
140
+
141
+ // ⑨ 明确要求带解读:只在这种改写句里才自动开,避免默认输出变长
142
+ if (/解读|详解|详细说|说人话/.test(src) && !/不要解读|不用解读|别解读/.test(src)) {
143
+ patch.withInterpret = true;
144
+ labels.push({ key: 'withInterpret', label: '解读', value: true, display: '附解析与详解' });
145
+ }
146
+
147
+ return { text: src, patch, labels, ignored };
148
+ }
149
+
150
+ export const REVISE_SYSTEMS = SYSTEMS;
151
+ export const REVISE_DIRECTIONS = DIRECTIONS;
152
+
153
+ /** 回显旧值:系统/性别/方向翻成中文,布尔翻成开/关,日期只留年份 */
154
+ export function displayValue(key, value) {
155
+ if (value === undefined || value === null) return null;
156
+ if (key === 'system') { const s = SYSTEMS.find((x) => x.key === value); return s ? s.label : String(value); }
157
+ if (key === 'gender') return value === 'female' ? '女' : value === 'male' ? '男' : String(value);
158
+ if (key === 'direction') { const d = DIRECTIONS.find((x) => x.key === value); return d ? d.label : String(value); }
159
+ if (typeof value === 'boolean') return value ? '开' : '关';
160
+ if (key === 'asOf') { const m = String(value).match(/^(\d{4})/); return m ? `${m[1]} 年` : String(value); }
161
+ return String(value);
162
+ }