dsh-metaphysics 0.18.4 → 0.19.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 +10 -0
- package/README.md +12 -11
- package/client.js +440 -17
- package/engine/almanac.js +137 -3
- package/engine/convert.js +137 -0
- package/engine/geo.js +1 -1
- package/engine/index.js +51 -5
- package/engine/zeri.js +29 -2
- package/index.js +15 -5
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +2 -2
package/engine/almanac.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// 彭祖百忌、胎神等全量黄历数据未收录——输出里如实标注「未收录」,不臆造。
|
|
8
8
|
// 宜忌只按「建除十二神」通行简表给出(传统择日的第一层判据),不是逐日全量黄历。
|
|
9
9
|
import { solarToLunar } from './lunar.js';
|
|
10
|
+
import { nayinOf } from './nayin.js';
|
|
10
11
|
import {
|
|
11
12
|
toJDN, fromJDN, dayGanzhiIndex, ganzhiName, termWindow, termInstantJd, partsToJd, STEMS, BRANCHES, TERM_NAMES,
|
|
12
13
|
} from './calendar.js';
|
|
@@ -89,6 +90,89 @@ export function lunarMonthText(month, isLeap = false) {
|
|
|
89
90
|
return `${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月`;
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
/** 黄道/黑道十二神(青龙、明堂…勾陈),值日与时家共用。 */
|
|
94
|
+
export const TIAN_SHEN = ['青龙', '明堂', '天刑', '朱雀', '金匮', '天德', '白虎', '玉堂', '天牢', '玄武', '司命', '勾陈'];
|
|
95
|
+
/** 六黄道(吉)/ 六黑道(凶)。 */
|
|
96
|
+
export const TIAN_SHEN_TYPE = {
|
|
97
|
+
青龙: '黄道', 明堂: '黄道', 金匮: '黄道', 天德: '黄道', 玉堂: '黄道', 司命: '黄道',
|
|
98
|
+
天刑: '黑道', 朱雀: '黑道', 白虎: '黑道', 天牢: '黑道', 玄武: '黑道', 勾陈: '黑道',
|
|
99
|
+
};
|
|
100
|
+
/** 十二神起例:以月支(日家)或日支(时家)为锚的偏移。 */
|
|
101
|
+
const TIAN_SHEN_OFFSET = { 子: 4, 丑: 2, 寅: 0, 卯: 10, 辰: 8, 巳: 6, 午: 4, 未: 2, 申: 0, 酉: 10, 戌: 8, 亥: 6 };
|
|
102
|
+
|
|
103
|
+
/** 日家十二神:日支 + 月支偏移;时家十二神:时支 + 日支偏移。 */
|
|
104
|
+
export function tianShenOf(branch, anchorBranch) {
|
|
105
|
+
const b = BRANCHES.indexOf(branch);
|
|
106
|
+
const off = TIAN_SHEN_OFFSET[anchorBranch];
|
|
107
|
+
if (b < 0 || off == null) return null;
|
|
108
|
+
const name = TIAN_SHEN[(b + off) % 12];
|
|
109
|
+
const type = TIAN_SHEN_TYPE[name];
|
|
110
|
+
return { name, type, luck: type === '黄道' ? '吉' : '凶' };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** 二十八宿:值日宿按「日支 + 星期」轮转(四组各七宿)。 */
|
|
114
|
+
export const MANSIONS = {
|
|
115
|
+
角: { luck: '吉', zheng: '木', animal: '蛟', gong: '东' }, 亢: { luck: '凶', zheng: '金', animal: '龙', gong: '东' },
|
|
116
|
+
氐: { luck: '凶', zheng: '土', animal: '貉', gong: '东' }, 房: { luck: '吉', zheng: '日', animal: '兔', gong: '东' },
|
|
117
|
+
心: { luck: '凶', zheng: '月', animal: '狐', gong: '东' }, 尾: { luck: '吉', zheng: '火', animal: '虎', gong: '东' },
|
|
118
|
+
箕: { luck: '吉', zheng: '水', animal: '豹', gong: '东' }, 斗: { luck: '吉', zheng: '木', animal: '獬', gong: '北' },
|
|
119
|
+
牛: { luck: '凶', zheng: '金', animal: '牛', gong: '北' }, 女: { luck: '凶', zheng: '土', animal: '蝠', gong: '北' },
|
|
120
|
+
虚: { luck: '凶', zheng: '日', animal: '鼠', gong: '北' }, 危: { luck: '凶', zheng: '月', animal: '燕', gong: '北' },
|
|
121
|
+
室: { luck: '吉', zheng: '火', animal: '猪', gong: '北' }, 壁: { luck: '吉', zheng: '水', animal: '獝', gong: '北' },
|
|
122
|
+
奎: { luck: '凶', zheng: '木', animal: '狼', gong: '西' }, 娄: { luck: '吉', zheng: '金', animal: '狗', gong: '西' },
|
|
123
|
+
胃: { luck: '吉', zheng: '土', animal: '彘', gong: '西' }, 昴: { luck: '凶', zheng: '日', animal: '鸡', gong: '西' },
|
|
124
|
+
毕: { luck: '吉', zheng: '月', animal: '乌', gong: '西' }, 觜: { luck: '凶', zheng: '火', animal: '猴', gong: '西' },
|
|
125
|
+
参: { luck: '吉', zheng: '水', animal: '猿', gong: '西' }, 井: { luck: '吉', zheng: '木', animal: '犴', gong: '南' },
|
|
126
|
+
鬼: { luck: '凶', zheng: '金', animal: '羊', gong: '南' }, 柳: { luck: '凶', zheng: '土', animal: '獐', gong: '南' },
|
|
127
|
+
星: { luck: '凶', zheng: '日', animal: '马', gong: '南' }, 张: { luck: '吉', zheng: '月', animal: '鹿', gong: '南' },
|
|
128
|
+
翼: { luck: '凶', zheng: '火', animal: '蛇', gong: '南' }, 轸: { luck: '吉', zheng: '水', animal: '蚓', gong: '南' },
|
|
129
|
+
};
|
|
130
|
+
const XIU_GROUPS = {
|
|
131
|
+
A: ['虚', '毕', '翼', '箕', '奎', '鬼', '氐'],
|
|
132
|
+
B: ['房', '危', '觜', '轸', '斗', '娄', '柳'],
|
|
133
|
+
C: ['星', '心', '室', '参', '角', '牛', '胃'],
|
|
134
|
+
D: ['昴', '张', '尾', '壁', '井', '亢', '女'],
|
|
135
|
+
};
|
|
136
|
+
const XIU_GROUP_OF = { 子: 'A', 辰: 'A', 申: 'A', 丑: 'B', 巳: 'B', 酉: 'B', 寅: 'C', 午: 'C', 戌: 'C', 卯: 'D', 未: 'D', 亥: 'D' };
|
|
137
|
+
|
|
138
|
+
/** 值日宿:weekday 0=周日。 */
|
|
139
|
+
export function xiuOf(dayBranch, weekdayIndex) {
|
|
140
|
+
const g = XIU_GROUP_OF[dayBranch];
|
|
141
|
+
if (!g) return null;
|
|
142
|
+
const name = XIU_GROUPS[g][weekdayIndex];
|
|
143
|
+
const info = MANSIONS[name];
|
|
144
|
+
return info ? { name, ...info } : null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** 吉神方位(按日干;福神取通行一变,另一变注明差异)。 */
|
|
148
|
+
const DIR_OF = { 坎: '正北', 艮: '东北', 震: '正东', 巽: '东南', 离: '正南', 坤: '西南', 兑: '正西', 乾: '西北' };
|
|
149
|
+
const POS_XI = { 甲: '艮', 乙: '乾', 丙: '坤', 丁: '离', 戊: '巽', 己: '艮', 庚: '乾', 辛: '坤', 壬: '离', 癸: '巽' };
|
|
150
|
+
const POS_CAI = { 甲: '艮', 乙: '艮', 丙: '坤', 丁: '坤', 戊: '坎', 己: '坎', 庚: '震', 辛: '震', 壬: '离', 癸: '离' };
|
|
151
|
+
const POS_FU = { 甲: '坎', 乙: '坤', 丙: '乾', 丁: '巽', 戊: '艮', 己: '坎', 庚: '坤', 辛: '乾', 壬: '巽', 癸: '艮' };
|
|
152
|
+
const POS_YANG_GUI = { 甲: '坤', 乙: '坤', 丙: '兑', 丁: '乾', 戊: '艮', 己: '坎', 庚: '离', 辛: '艮', 壬: '震', 癸: '巽' };
|
|
153
|
+
const POS_YIN_GUI = { 甲: '艮', 乙: '坎', 丙: '乾', 丁: '兑', 戊: '坤', 己: '坤', 庚: '艮', 辛: '离', 壬: '巽', 癸: '震' };
|
|
154
|
+
const posOf = (map, stem) => (map[stem] ? { gua: map[stem], dir: DIR_OF[map[stem]] } : null);
|
|
155
|
+
|
|
156
|
+
/** 胎神(逐日干支,通行表)。 */
|
|
157
|
+
const TAI_SHEN = {
|
|
158
|
+
甲子: '占门碓 外东南', 乙丑: '碓磨厕 外东南', 丙寅: '厨灶炉 外正南', 丁卯: '仓库门 外正南', 戊辰: '房床栖 外正南',
|
|
159
|
+
己巳: '占门床 外正南', 庚午: '占碓磨 外正南', 辛未: '厨灶厕 外西南', 壬申: '仓库炉 外西南', 癸酉: '房床门 外西南',
|
|
160
|
+
甲戌: '占门栖 外西南', 乙亥: '碓磨床 外西南', 丙子: '厨灶碓 外西南', 丁丑: '仓库厕 外正西', 戊寅: '房床炉 外正西',
|
|
161
|
+
己卯: '占大门 外正西', 庚辰: '碓磨栖 外正西', 辛巳: '厨灶床 外正西', 壬午: '仓库碓 外西北', 癸未: '房床厕 外西北',
|
|
162
|
+
甲申: '占门炉 外西北', 乙酉: '碓磨门 外西北', 丙戌: '厨灶栖 外西北', 丁亥: '仓库床 外西北', 戊子: '房床碓 外正北',
|
|
163
|
+
己丑: '占门厕 外正北', 庚寅: '碓磨炉 外正北', 辛卯: '厨灶门 外正北', 壬辰: '仓库栖 外正北', 癸巳: '占房床 房内北',
|
|
164
|
+
甲午: '占门碓 房内北', 乙未: '碓磨厕 房内北', 丙申: '厨灶炉 房内北', 丁酉: '仓库门 房内北', 戊戌: '房床栖 房内中',
|
|
165
|
+
己亥: '占门床 房内中', 庚子: '占碓磨 房内南', 辛丑: '厨灶厕 房内南', 壬寅: '仓库炉 房内南', 癸卯: '房床门 房内西',
|
|
166
|
+
甲辰: '占门栖 房内东', 乙巳: '碓磨床 房内东', 丙午: '厨灶碓 房内东', 丁未: '仓库厕 房内东', 戊申: '房床炉 房内中',
|
|
167
|
+
己酉: '占大门 外东北', 庚戌: '碓磨栖 外东北', 辛亥: '厨灶床 外东北', 壬子: '仓库碓 外东北', 癸丑: '房床厕 外东北',
|
|
168
|
+
甲寅: '占门炉 外东北', 乙卯: '碓磨门 外正东', 丙辰: '厨灶栖 外正东', 丁巳: '仓库床 外正东', 戊午: '房床碓 外正东',
|
|
169
|
+
己未: '占门厕 外正东', 庚申: '碓磨炉 外东南', 辛酉: '厨灶门 外东南', 壬戌: '仓库栖 外东南', 癸亥: '占房床 外东南',
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/** 六合 / 三合(对日支取吉配生肖)。 */
|
|
173
|
+
const LIUHE = { 子: '丑', 丑: '子', 寅: '亥', 亥: '寅', 卯: '戌', 戌: '卯', 辰: '酉', 酉: '辰', 巳: '申', 申: '巳', 午: '未', 未: '午' };
|
|
174
|
+
const SANHE = { 申: '申子辰', 子: '申子辰', 辰: '申子辰', 亥: '亥卯未', 卯: '亥卯未', 未: '亥卯未', 寅: '寅午戌', 午: '寅午戌', 戌: '寅午戌', 巳: '巳酉丑', 酉: '巳酉丑', 丑: '巳酉丑' };
|
|
175
|
+
|
|
92
176
|
/** 每日一卦:日期哈希确定性映射到通行本 64 卦(同日同卦)。 */
|
|
93
177
|
export function dailyHexagram(year, month, day) {
|
|
94
178
|
const names = Object.keys(HEX64);
|
|
@@ -153,7 +237,42 @@ export function buildAlmanac(input) {
|
|
|
153
237
|
return `${p.year}-${String(p.month).padStart(2, '0')}-${String(p.day).padStart(2, '0')}`;
|
|
154
238
|
};
|
|
155
239
|
|
|
156
|
-
const
|
|
240
|
+
const weekdayIdx = (jdn + 1) % 7;
|
|
241
|
+
const weekday = ['日', '一', '二', '三', '四', '五', '六'][weekdayIdx];
|
|
242
|
+
// 值日十二神(黄道/黑道)、二十八宿、胎神、纳音、吉神方位、时辰吉凶
|
|
243
|
+
const dayGod = tianShenOf(dayBranch, BRANCHES[monthBranchIdx]);
|
|
244
|
+
const xiu = xiuOf(dayBranch, weekdayIdx);
|
|
245
|
+
const taiShen = TAI_SHEN[dayGz.name] || null;
|
|
246
|
+
const hourBase = (STEMS.indexOf(dayGz.stem) % 5) * 2;
|
|
247
|
+
const hours = BRANCHES.map((zhi, i) => {
|
|
248
|
+
const gan = STEMS[(hourBase + i) % 10];
|
|
249
|
+
const gz = ganzhiName(hourComposite((hourBase + i) % 10, i));
|
|
250
|
+
const shen = tianShenOf(zhi, dayBranch);
|
|
251
|
+
return {
|
|
252
|
+
zhi,
|
|
253
|
+
name: `${zhi}时`,
|
|
254
|
+
ganZhi: gz.name,
|
|
255
|
+
gan,
|
|
256
|
+
shen: shen ? shen.name : null,
|
|
257
|
+
type: shen ? shen.type : null,
|
|
258
|
+
luck: shen ? shen.luck : null,
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
const sanheGroup = SANHE[dayBranch] || '';
|
|
262
|
+
const liuheBranch = LIUHE[dayBranch] || null;
|
|
263
|
+
const lucky = {
|
|
264
|
+
liuhe: liuheBranch ? SHENGXIAO[BRANCHES.indexOf(liuheBranch)] : null,
|
|
265
|
+
sanhe: [...sanheGroup].filter((b) => b !== dayBranch).map((b) => SHENGXIAO[BRANCHES.indexOf(b)]),
|
|
266
|
+
};
|
|
267
|
+
const positions = {
|
|
268
|
+
caiShen: CAI_SHEN[dayGz.stem] || null,
|
|
269
|
+
xiShen: XI_SHEN[dayGz.stem] || null,
|
|
270
|
+
fuShen: posOf(POS_FU, dayGz.stem),
|
|
271
|
+
yangGui: posOf(POS_YANG_GUI, dayGz.stem),
|
|
272
|
+
yinGui: posOf(POS_YIN_GUI, dayGz.stem),
|
|
273
|
+
xiShenFull: posOf(POS_XI, dayGz.stem),
|
|
274
|
+
caiShenFull: posOf(POS_CAI, dayGz.stem),
|
|
275
|
+
};
|
|
157
276
|
const lunarText = `农历${springGz.name}年${lunarMonthText(lunar.month, lunar.isLeap)}${dayText(lunar.day)}`;
|
|
158
277
|
const boundaryNote = yearGz.name !== springGz.name
|
|
159
278
|
? `年界:本条按立春界作${yearGz.name}年·属${SHENGXIAO[BRANCHES.indexOf(yearGz.branch)]}(命理排盘用);春节界为${springGz.name}年·属${SHENGXIAO[BRANCHES.indexOf(springGz.branch)]},两种都对,取用场合不同`
|
|
@@ -165,7 +284,7 @@ export function buildAlmanac(input) {
|
|
|
165
284
|
date: `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
|
|
166
285
|
weekday: `星期${weekday}`,
|
|
167
286
|
...(boundaryNote ? { boundaryNote } : {}),
|
|
168
|
-
scope: '
|
|
287
|
+
scope: '通行口径:宜忌按建除十二神简表;已收录值日十二神(黄道/黑道)、时辰吉凶、二十八宿、胎神、吉神方位、纳音、六合三合吉配;逐日全量吉神凶煞与彭祖百忌未收录',
|
|
169
288
|
},
|
|
170
289
|
lunar: {
|
|
171
290
|
year: springYear,
|
|
@@ -186,7 +305,13 @@ export function buildAlmanac(input) {
|
|
|
186
305
|
prev: prevTerm ? { name: termName(prevTerm), date: fmtJdDate(prevTerm.jd) } : null,
|
|
187
306
|
next: nextTerm ? { name: termName(nextTerm), date: fmtJdDate(nextTerm.jd) } : null,
|
|
188
307
|
},
|
|
189
|
-
positions
|
|
308
|
+
positions,
|
|
309
|
+
dayGod,
|
|
310
|
+
xiu,
|
|
311
|
+
taiShen,
|
|
312
|
+
nayin: { day: nayinOf(dayGanzhiIndex(jdn)) },
|
|
313
|
+
lucky,
|
|
314
|
+
hours,
|
|
190
315
|
zhiXing,
|
|
191
316
|
yi: ZHIXING_YI[zhiXing].slice(),
|
|
192
317
|
ji: ZHIXING_JI[zhiXing].slice(),
|
|
@@ -199,6 +324,7 @@ export function buildAlmanac(input) {
|
|
|
199
324
|
sources: [
|
|
200
325
|
'农历与节气:本地天文历法(定朔 + 节气黄经)',
|
|
201
326
|
'建除十二神与冲煞:传统通行口径',
|
|
327
|
+
'值日/时家十二神(青龙…勾陈)、二十八宿、胎神、吉神方位:通行表',
|
|
202
328
|
'宜忌:建除十二神通行简表(非逐日全量黄历)',
|
|
203
329
|
'每日一卦:按公历日期确定性取卦(同日同卦)',
|
|
204
330
|
],
|
|
@@ -213,3 +339,11 @@ function monthComposite(stemIdx, branchIdx) {
|
|
|
213
339
|
}
|
|
214
340
|
return 0;
|
|
215
341
|
}
|
|
342
|
+
|
|
343
|
+
/** 由时干序与时支序求六十甲子序。 */
|
|
344
|
+
function hourComposite(stemIdx, branchIdx) {
|
|
345
|
+
for (let i = 0; i < 60; i++) {
|
|
346
|
+
if (i % 10 === stemIdx && i % 12 === branchIdx) return i;
|
|
347
|
+
}
|
|
348
|
+
return 0;
|
|
349
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// 公农历互转(本地确定性,不依赖外部历法库)
|
|
2
|
+
//
|
|
3
|
+
// 两种方向:
|
|
4
|
+
// · 公历 → 农历:直接查本地定朔历(engine/lunar.js),给出农历年月日、闰月标记、干支、生肖。
|
|
5
|
+
// · 农历 → 公历:按目标农历年的「月首」序列反查(每月 29/30 天,闰月单独一轮),
|
|
6
|
+
// 逐月定位后再加日偏移;不做「节气月」换算,农历就是朔望月口径。
|
|
7
|
+
//
|
|
8
|
+
// 诚实边界:只处理 1900–2100 的本地历法覆盖范围(与 lunar.js 一致);闰月必须显式给出,
|
|
9
|
+
// 不猜「第一个同名月」;农历日期越界(如小月三十)如实报错,不静默回退。
|
|
10
|
+
import { solarToLunar } from './lunar.js';
|
|
11
|
+
import { fromJDN, toJDN } from './calendar.js';
|
|
12
|
+
import { buildAlmanac } from './almanac.js';
|
|
13
|
+
import { assertCivil, daysInMonth } from './validate.js';
|
|
14
|
+
|
|
15
|
+
const WEEK = ['日', '一', '二', '三', '四', '五', '六'];
|
|
16
|
+
const MONTH_TEXT = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊'];
|
|
17
|
+
const DAY_TENS = ['初', '十', '廿'];
|
|
18
|
+
const DAY_UNITS = ['十', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
|
|
19
|
+
|
|
20
|
+
function dayText(day) {
|
|
21
|
+
if (day === 10) return '初十';
|
|
22
|
+
if (day === 20) return '二十';
|
|
23
|
+
if (day === 30) return '三十';
|
|
24
|
+
return `${DAY_TENS[Math.floor(day / 10)]}${DAY_UNITS[day % 10]}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function lunarText(year, month, day, isLeap) {
|
|
28
|
+
return `农历${year}年${isLeap ? '闰' : ''}${MONTH_TEXT[month - 1] || month}月${dayText(day)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 找某个农历年的正月初一(公历 1/20–2/25 之间)。 */
|
|
32
|
+
function lunarNewYearJdn(lunarYear) {
|
|
33
|
+
const from = toJDN(lunarYear, 1, 20);
|
|
34
|
+
const to = toJDN(lunarYear, 2, 25);
|
|
35
|
+
for (let jdn = from; jdn <= to; jdn++) {
|
|
36
|
+
const p = fromJDN(jdn);
|
|
37
|
+
const l = solarToLunar(p.year, p.month, p.day);
|
|
38
|
+
if (l.lunarYear === lunarYear && l.month === 1 && l.day === 1) return jdn;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** 某农历年的月首序列(含闰月)。 */
|
|
44
|
+
function lunarMonths(lunarYear) {
|
|
45
|
+
const first = lunarNewYearJdn(lunarYear);
|
|
46
|
+
if (first == null) return [];
|
|
47
|
+
const out = [];
|
|
48
|
+
let cur = first;
|
|
49
|
+
for (let i = 0; i < 14; i++) {
|
|
50
|
+
const p = fromJDN(cur);
|
|
51
|
+
const l = solarToLunar(p.year, p.month, p.day);
|
|
52
|
+
if (i > 0 && l.month === 1 && !l.isLeap) break;
|
|
53
|
+
let next = null;
|
|
54
|
+
for (let k = 29; k <= 31; k++) {
|
|
55
|
+
const d = fromJDN(cur + k);
|
|
56
|
+
const l2 = solarToLunar(d.year, d.month, d.day);
|
|
57
|
+
if (l2.day === 1) { next = cur + k; break; }
|
|
58
|
+
}
|
|
59
|
+
if (next == null) break;
|
|
60
|
+
out.push({ month: l.month, isLeap: l.isLeap, startJdn: cur, length: next - cur });
|
|
61
|
+
cur = next;
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 公农历互转。
|
|
68
|
+
* @param {{mode?:'solar2lunar'|'lunar2solar', year?:number, month?:number, day?:number,
|
|
69
|
+
* lunarYear?:number, lunarMonth?:number, lunarDay?:number, isLeapMonth?:boolean}} input
|
|
70
|
+
*/
|
|
71
|
+
export function buildConvert(input) {
|
|
72
|
+
const mode = input.mode === 'lunar2solar' ? 'lunar2solar' : 'solar2lunar';
|
|
73
|
+
let solar;
|
|
74
|
+
let lunar;
|
|
75
|
+
let note = null;
|
|
76
|
+
if (mode === 'solar2lunar') {
|
|
77
|
+
solar = { year: input.year, month: input.month, day: input.day };
|
|
78
|
+
assertCivil(solar, '公农历转换');
|
|
79
|
+
if (solar.day > daysInMonth(solar.year, solar.month)) {
|
|
80
|
+
throw new Error(`非法日期:${solar.year} 年 ${solar.month} 月没有 ${solar.day} 日`);
|
|
81
|
+
}
|
|
82
|
+
lunar = solarToLunar(solar.year, solar.month, solar.day);
|
|
83
|
+
} else {
|
|
84
|
+
const y = Number(input.lunarYear);
|
|
85
|
+
const m = Number(input.lunarMonth);
|
|
86
|
+
const d = Number(input.lunarDay);
|
|
87
|
+
if (![y, m, d].every(Number.isInteger)) throw new Error('农历转换需要 lunarYear / lunarMonth / lunarDay');
|
|
88
|
+
if (m < 1 || m > 12) throw new Error('农历月份须在 1–12');
|
|
89
|
+
const months = lunarMonths(y);
|
|
90
|
+
if (!months.length) throw new Error(`农历 ${y} 年超出本地历法覆盖范围(1900–2100)`);
|
|
91
|
+
const isLeap = input.isLeapMonth === true;
|
|
92
|
+
const hit = months.find((x) => x.month === m && x.isLeap === isLeap);
|
|
93
|
+
if (!hit) {
|
|
94
|
+
const leapMonths = months.filter((x) => x.isLeap).map((x) => `闰${MONTH_TEXT[x.month - 1]}月`);
|
|
95
|
+
throw new Error(`农历 ${y} 年没有${leapMonths.length ? `该月(该年闰月为 ${leapMonths.join('、')})` : '闰月'}:${isLeap ? '请确认闰月标记' : '请确认月份'}`);
|
|
96
|
+
}
|
|
97
|
+
if (d < 1 || d > hit.length) throw new Error(`农历 ${y} 年${isLeap ? '闰' : ''}${MONTH_TEXT[m - 1]}月只有 ${hit.length} 天,没有 ${d} 日`);
|
|
98
|
+
const p = fromJDN(hit.startJdn + d - 1);
|
|
99
|
+
solar = { year: p.year, month: p.month, day: p.day };
|
|
100
|
+
const check = solarToLunar(p.year, p.month, p.day);
|
|
101
|
+
if (check.month !== m || check.day !== d || check.isLeap !== isLeap) {
|
|
102
|
+
note = '反查结果与目标农历日不完全一致,已按本地历法实际月首回推';
|
|
103
|
+
}
|
|
104
|
+
lunar = check;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const a = buildAlmanac(solar);
|
|
108
|
+
const jdn = toJDN(solar.year, solar.month, solar.day);
|
|
109
|
+
const solarText = `${solar.year}-${String(solar.month).padStart(2, '0')}-${String(solar.day).padStart(2, '0')}`;
|
|
110
|
+
return {
|
|
111
|
+
system: 'convert',
|
|
112
|
+
meta: {
|
|
113
|
+
mode,
|
|
114
|
+
solarDate: solarText,
|
|
115
|
+
weekday: `星期${WEEK[(jdn + 1) % 7]}`,
|
|
116
|
+
...(note ? { note } : {}),
|
|
117
|
+
scope: '公农历互转按本地定朔历(1900–2100);农历闰月须显式指定,不自动猜同名月',
|
|
118
|
+
},
|
|
119
|
+
solar: { year: solar.year, month: solar.month, day: solar.day, text: solarText },
|
|
120
|
+
lunar: {
|
|
121
|
+
year: lunar.lunarYear,
|
|
122
|
+
month: lunar.month,
|
|
123
|
+
day: lunar.day,
|
|
124
|
+
isLeap: lunar.isLeap,
|
|
125
|
+
text: lunarText(lunar.lunarYear, lunar.month, lunar.day, lunar.isLeap),
|
|
126
|
+
},
|
|
127
|
+
ganzhi: {
|
|
128
|
+
year: a.ganzhi.year,
|
|
129
|
+
month: a.ganzhi.month,
|
|
130
|
+
day: a.ganzhi.day,
|
|
131
|
+
shengXiao: a.ganzhi.shengXiao,
|
|
132
|
+
springYear: a.ganzhi.springYear,
|
|
133
|
+
},
|
|
134
|
+
sources: ['农历:本地定朔 + 节气黄经历法(engine/lunar.js)', '干支与生肖:与黄历同口径(年按立春界,另列春节界)'],
|
|
135
|
+
disclaimer: '历法换算为确定性计算;民俗历法各版本在极少数日期(交节当日、闰月边界)存在日界差异,已注明口径。',
|
|
136
|
+
};
|
|
137
|
+
}
|
package/engine/geo.js
CHANGED
|
@@ -143,7 +143,7 @@ const DETAIL = /(区|县|镇|乡|村|小区|街道|路|号|巷|弄|组|队)/;
|
|
|
143
143
|
|
|
144
144
|
/** OpenStreetMap Nominatim:免密钥、支持中文。失败返回 null。
|
|
145
145
|
* UA 按 OSM 使用政策要求写明应用与联系方式(改版本时同步这里)。 */
|
|
146
|
-
const USER_AGENT = 'dsh-metaphysics/0.
|
|
146
|
+
const USER_AGENT = 'dsh-metaphysics/0.19.0 (+https://github.com/xuanfu-web/dsh-metaphysics)';
|
|
147
147
|
|
|
148
148
|
async function onlineLookup(text, { timeoutMs = 2500 } = {}) {
|
|
149
149
|
if (typeof fetch !== 'function') return null;
|
package/engine/index.js
CHANGED
|
@@ -21,7 +21,8 @@ import { buildZeri } from './zeri.js';
|
|
|
21
21
|
import { buildChenggu } from './chenggu.js';
|
|
22
22
|
import { buildXiaoliuren } from './xiaoliuren.js';
|
|
23
23
|
import { buildStar } from './star.js';
|
|
24
|
-
import { buildNumerology } from './numerology.js';
|
|
24
|
+
import { buildNumerology } from './numerology.js';
|
|
25
|
+
import { buildConvert } from './convert.js';
|
|
25
26
|
import { buildTrend } from './trend.js';
|
|
26
27
|
import { buildFengshui } from './fengshui.js';
|
|
27
28
|
import { buildName } from './name.js';
|
|
@@ -617,6 +618,26 @@ function computeRaw(args = {}) {
|
|
|
617
618
|
const result = buildChenggu({ year: dt.year, month: dt.month, day: dt.day, hour, minute: hasTime ? dt.minute : 0 });
|
|
618
619
|
return { ...result, summary: chengguText(result) };
|
|
619
620
|
}
|
|
621
|
+
if (system === 'convert') {
|
|
622
|
+
const mode = args.mode === 'lunar2solar' ? 'lunar2solar' : 'solar2lunar';
|
|
623
|
+
let result;
|
|
624
|
+
if (mode === 'lunar2solar') {
|
|
625
|
+
if (args.lunarYear == null || args.lunarMonth == null || args.lunarDay == null) {
|
|
626
|
+
throw fail('E_INPUT', '农历转公历需要 lunarYear / lunarMonth / lunarDay(闰月另加 isLeapMonth: true)');
|
|
627
|
+
}
|
|
628
|
+
result = buildConvert({
|
|
629
|
+
mode,
|
|
630
|
+
lunarYear: Number(args.lunarYear),
|
|
631
|
+
lunarMonth: Number(args.lunarMonth),
|
|
632
|
+
lunarDay: Number(args.lunarDay),
|
|
633
|
+
isLeapMonth: args.isLeapMonth === true,
|
|
634
|
+
});
|
|
635
|
+
} else {
|
|
636
|
+
const dt = parseDateTime(args.datetime);
|
|
637
|
+
result = buildConvert({ mode, year: dt.year, month: dt.month, day: dt.day });
|
|
638
|
+
}
|
|
639
|
+
return { ...result, summary: convertText(result) };
|
|
640
|
+
}
|
|
620
641
|
if (system === 'xiaoliuren') {
|
|
621
642
|
const dt = args.datetime ? parseDateTime(args.datetime) : null;
|
|
622
643
|
const result = buildXiaoliuren({
|
|
@@ -700,22 +721,35 @@ function computeRaw(args = {}) {
|
|
|
700
721
|
return { ...result, summary: nameText(result) };
|
|
701
722
|
}
|
|
702
723
|
if (!system) {
|
|
703
|
-
throw fail('E_INPUT', '缺少 system,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name
|
|
724
|
+
throw fail('E_INPUT', '缺少 system,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name(起名)、convert(公农历互转)。');
|
|
704
725
|
}
|
|
705
|
-
throw fail('E_SYSTEM', `未知体系「${system}」,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name
|
|
726
|
+
throw fail('E_SYSTEM', `未知体系「${system}」,可选:bazi(四柱八字)、ziwei(紫微斗数)、liuyao(六爻)、meihua(梅花易数)、daliuren(大六壬)、qimen(奇门遁甲)、hepan(合盘)、tarot(塔罗)、almanac(黄历)、zeri(择日)、chenggu(称骨)、xiaoliuren(小六壬)、star(星座)、numerology(生命数字)、trend(人生 K 线)、fengshui(风水)、name(起名)、convert(公农历互转)。`);
|
|
706
727
|
}
|
|
707
728
|
|
|
708
729
|
/** 黄历文本 */
|
|
709
730
|
function almanacText(r) {
|
|
710
731
|
const g = r.ganzhi;
|
|
711
732
|
const jq = r.jieQi && r.jieQi.next ? ` 下一节:${r.jieQi.next.name} ${r.jieQi.next.date}` : '';
|
|
733
|
+
const god = r.dayGod ? `值日:${r.dayGod.name}(${r.dayGod.type}·${r.dayGod.luck})` : '';
|
|
734
|
+
const xiu = r.xiu ? `二十八宿:${r.xiu.name}宿(${r.xiu.luck}·${r.xiu.zheng}·${r.xiu.animal})` : '';
|
|
735
|
+
const tai = r.taiShen ? `胎神:${r.taiShen}` : '';
|
|
736
|
+
const pos = r.positions
|
|
737
|
+
? `吉神方位:喜神${r.positions.xiShen || '—'} 财神${r.positions.caiShen || '—'} 福神${r.positions.fuShen ? r.positions.fuShen.dir : '—'} 阳贵${r.positions.yangGui ? r.positions.yangGui.dir : '—'} 阴贵${r.positions.yinGui ? r.positions.yinGui.dir : '—'}`
|
|
738
|
+
: '';
|
|
739
|
+
const lucky = r.lucky ? `吉配生肖:六合${r.lucky.liuhe || '—'} 三合${(r.lucky.sanhe || []).join('、') || '—'}` : '';
|
|
740
|
+
const nayin = r.nayin && r.nayin.day ? `日柱纳音:${r.nayin.day.name}` : '';
|
|
741
|
+
const hours = (r.hours || []).map((h) => `${h.zhi}${h.ganZhi.slice(0, 1)}·${h.shen}${h.luck === '吉' ? '吉' : '凶'}`).join(' ');
|
|
712
742
|
return [
|
|
713
743
|
`【黄历】${r.meta.date} ${r.meta.weekday} ${r.lunar.text}`,
|
|
714
744
|
`干支:${g.year}年 ${g.month}月 ${g.day}日 属${g.shengXiao}`,
|
|
715
745
|
...(r.meta.boundaryNote ? [` ${r.meta.boundaryNote}`] : []),
|
|
716
|
-
`建除:${r.zhiXing}日 冲:${r.chong.text}${r.chong.sha ? `(${r.chong.sha})` : ''}
|
|
746
|
+
`建除:${r.zhiXing}日 冲:${r.chong.text}${r.chong.sha ? `(${r.chong.sha})` : ''} ${god}`,
|
|
747
|
+
[xiu, nayin, tai].filter(Boolean).join(' '),
|
|
717
748
|
`宜:${r.yi.join('、')}`,
|
|
718
749
|
`忌:${r.ji.join('、')}`,
|
|
750
|
+
pos,
|
|
751
|
+
lucky,
|
|
752
|
+
hours ? `时辰吉凶:${hours}` : '',
|
|
719
753
|
`节气:上一节 ${r.jieQi.prev ? `${r.jieQi.prev.name} ${r.jieQi.prev.date}` : '—'}${jq}`,
|
|
720
754
|
r.dailyHexagram ? `每日一卦:${r.dailyHexagram.name} ${r.dailyHexagram.meaning || ''}` : '',
|
|
721
755
|
`口径:${r.meta.scope}`,
|
|
@@ -775,6 +809,18 @@ function starText(r) {
|
|
|
775
809
|
].join('\n');
|
|
776
810
|
}
|
|
777
811
|
|
|
812
|
+
/** 公农历互转文本 */
|
|
813
|
+
function convertText(r) {
|
|
814
|
+
const g = r.ganzhi;
|
|
815
|
+
const dir = r.meta.mode === 'lunar2solar' ? '农历 → 公历' : '公历 → 农历';
|
|
816
|
+
return [
|
|
817
|
+
`【公农历转换·${dir}】${r.lunar.text} ⇄ ${r.solar.text} ${r.meta.weekday}`,
|
|
818
|
+
`干支:${g.year}年 ${g.month}月 ${g.day}日 属${g.shengXiao}${g.springYear && g.springYear !== g.year ? `(春节界为${g.springYear}年)` : ''}`,
|
|
819
|
+
...(r.meta.note ? [`注:${r.meta.note}`] : []),
|
|
820
|
+
`口径:${r.meta.scope}`,
|
|
821
|
+
].join('\n');
|
|
822
|
+
}
|
|
823
|
+
|
|
778
824
|
/** 生命数字文本 */
|
|
779
825
|
function numerologyText(r) {
|
|
780
826
|
return [
|
|
@@ -883,7 +929,7 @@ export { buildBazi, buildLiuyao, tossLines };
|
|
|
883
929
|
export { followup };
|
|
884
930
|
export { pastSignals, verifyFit, rectifyBirth };
|
|
885
931
|
export { crossCheck, crossText };
|
|
886
|
-
export { buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buildNumerology };
|
|
932
|
+
export { buildAlmanac, buildZeri, buildChenggu, buildXiaoliuren, buildStar, buildNumerology, buildConvert };
|
|
887
933
|
export { buildTrend, buildFengshui, buildName };
|
|
888
934
|
|
|
889
935
|
|
package/engine/zeri.js
CHANGED
|
@@ -7,27 +7,54 @@ import { buildAlmanac, SHENGXIAO } from './almanac.js';
|
|
|
7
7
|
export const TASKS = {
|
|
8
8
|
嫁娶: { yi: ['嫁娶', '结亲', '订盟', '纳采'], related: ['会亲友', '裁衣'], category: 'marriage' },
|
|
9
9
|
订婚: { yi: ['订盟', '纳采'], related: ['嫁娶', '会亲友'], category: 'marriage' },
|
|
10
|
+
领证: { yi: ['嫁娶', '纳采'], related: ['订盟', '会亲友'], category: 'marriage' },
|
|
11
|
+
提亲: { yi: ['纳采', '订盟'], related: ['会亲友'], category: 'marriage' },
|
|
12
|
+
收送聘金: { yi: ['纳采', '订盟'], related: ['嫁娶'], category: 'marriage' },
|
|
13
|
+
满月酒: { yi: ['祭祀', '祈福'], related: ['会亲友'], category: 'celebration' },
|
|
10
14
|
开业: { yi: ['开市', '立券', '交易'], related: ['纳财', '挂匾'], category: 'business' },
|
|
15
|
+
交易: { yi: ['交易', '立券'], related: ['开市', '纳财'], category: 'business' },
|
|
16
|
+
投资: { yi: ['纳财', '交易'], related: ['立券'], category: 'business' },
|
|
17
|
+
签订合同: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
18
|
+
签约: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
19
|
+
纳财: { yi: ['纳财', '收账'], related: ['开市', '立券'], category: 'contract' },
|
|
11
20
|
入宅: { yi: ['入宅', '移徙'], related: ['安床', '修造', '扫舍'], category: 'move' },
|
|
12
21
|
搬家: { yi: ['移徙', '入宅'], related: ['安床', '修造'], category: 'move' },
|
|
22
|
+
搬家入宅: { yi: ['入宅', '移徙'], related: ['安床', '扫舍'], category: 'move' },
|
|
13
23
|
动土: { yi: ['动土', '修造'], related: ['竖柱', '上梁'], category: 'construction' },
|
|
14
24
|
装修: { yi: ['修造', '修饰垣墙'], related: ['动土'], category: 'construction' },
|
|
25
|
+
装修建造: { yi: ['修造', '动土'], related: ['竖柱', '上梁'], category: 'construction' },
|
|
26
|
+
试车买车: { yi: ['交易', '纳财'], related: ['出行'], category: 'purchase' },
|
|
15
27
|
安葬: { yi: ['安葬', '破土'], related: ['立碑', '埋穴'], category: 'burial' },
|
|
16
28
|
出行: { yi: ['出行'], related: ['上任', '赴任'], category: 'travel' },
|
|
29
|
+
旅行: { yi: ['出行'], related: ['上任', '赴任'], category: 'travel' },
|
|
30
|
+
赴任: { yi: ['上任', '赴任'], related: ['出行'], category: 'travel' },
|
|
31
|
+
访亲友: { yi: ['会亲友'], related: ['出行'], category: 'visit' },
|
|
32
|
+
入学: { yi: ['入学'], related: ['开市', '修造'], category: 'study' },
|
|
17
33
|
祭祀: { yi: ['祭祀'], related: ['祈福', '求嗣'], category: 'worship' },
|
|
18
|
-
签约: { yi: ['立券', '交易'], related: ['纳财', '开市'], category: 'contract' },
|
|
19
34
|
求医: { yi: ['求医', '疗病'], related: ['针灸'], category: 'medical' },
|
|
20
|
-
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** 事项分组(界面按组呈现;与商用黄历的「常用/婚嫁/生活/建造/工商」对应)。 */
|
|
38
|
+
export const TASK_GROUPS = {
|
|
39
|
+
常用: ['嫁娶', '搬家入宅', '出行', '开业', '签订合同', '祭祀'],
|
|
40
|
+
婚嫁: ['嫁娶', '订婚', '领证', '提亲', '收送聘金', '满月酒'],
|
|
41
|
+
生活: ['搬家', '入宅', '旅行', '访亲友', '入学', '求医', '祭祀'],
|
|
42
|
+
建造: ['动土', '装修', '装修建造', '安葬', '试车买车'],
|
|
43
|
+
工商: ['开业', '交易', '投资', '签订合同', '签约', '纳财', '赴任'],
|
|
21
44
|
};
|
|
22
45
|
|
|
23
46
|
/** 建除十二神按事项大类的通行适配(简化口径)。 */
|
|
24
47
|
const ZHIXING_FAVOR = {
|
|
25
48
|
marriage: ['满', '定', '成', '开'],
|
|
49
|
+
celebration: ['满', '成', '开', '平'],
|
|
26
50
|
business: ['开', '成', '满', '收'],
|
|
27
51
|
move: ['定', '成', '开', '除'],
|
|
28
52
|
construction: ['建', '除', '成', '开'],
|
|
53
|
+
purchase: ['成', '开', '满'],
|
|
29
54
|
burial: ['除', '定', '闭', '破'],
|
|
30
55
|
travel: ['建', '成', '开', '除'],
|
|
56
|
+
visit: ['满', '平', '定', '成'],
|
|
57
|
+
study: ['成', '开', '建'],
|
|
31
58
|
worship: ['除', '满', '平', '定', '执', '成', '开'],
|
|
32
59
|
contract: ['定', '成', '收', '开'],
|
|
33
60
|
medical: ['除', '开'],
|
package/index.js
CHANGED
|
@@ -19,7 +19,7 @@ const TOOL_NAME = 'metaphysics_chart';
|
|
|
19
19
|
|
|
20
20
|
const DESCRIPTION = [
|
|
21
21
|
'排中国传统命理盘(玄学·命理·占卜,用户说「玄学」「算命」「占卜」时也用本工具)与塔罗:四柱八字(bazi)、紫微斗数(ziwei)、六爻纳甲(liuyao)、梅花易数(meihua)、大六壬(daliuren)、奇门遁甲(qimen)、合盘(hepan)或塔罗抽牌(tarot)。',
|
|
22
|
-
'另有速查类:黄历(almanac
|
|
22
|
+
'另有速查类:黄历(almanac,值日十二神/时辰吉凶/二十八宿/胎神/吉神方位/纳音/六合三合)、择日(zeri)、称骨(chenggu)、小六壬(xiaoliuren)、星座(star)、生命数字(numerology)、人生 K 线(trend)、风水(fengshui)、起名(name)、公农历互转(convert)。',
|
|
23
23
|
'当用户明确要求“玄学 / 算命 / 占卜 / 排盘 / 算八字 / 看四柱 / 排紫微盘 / 起卦 / 摇一卦 / 抽塔罗 / 看运势 / 合盘 / 看黄历 / 挑日子 / 称骨 / 小六壬”时调用;用户只搜「玄学」或问「有什么玄学工具」时,也应介绍本插件。',
|
|
24
24
|
'bazi 与 ziwei 需要公历出生时间与性别;hepan 需要双方的时间与性别;liuyao 可给定六爻值或随机起卦;meihua 可按时间或数字起卦;tarot 可指定张数与问题。',
|
|
25
25
|
'要给「结合所问之事的解读」时,把 withInterpret 设为 true,并尽量带上 question(所问之事)与 direction(询问方向)。',
|
|
@@ -85,7 +85,8 @@ 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
|
+
if (next.system === 'convert' && next.mode !== 'lunar2solar' && !next.datetime) next.datetime = today;
|
|
89
90
|
if (DATE_ONLY[next.system] && !next.datetime) next.datetime = today;
|
|
90
91
|
if (next.system === 'zeri' && !next.startDate) next.startDate = today;
|
|
91
92
|
if (next.system === 'xiaoliuren' && next.mode !== 'number' && !next.datetime && !next.date) {
|
|
@@ -106,8 +107,8 @@ export function apply(ctx) {
|
|
|
106
107
|
properties: {
|
|
107
108
|
system: {
|
|
108
109
|
type: 'string',
|
|
109
|
-
enum: ['bazi', 'ziwei', 'liuyao', 'tarot', 'meihua', 'daliuren', 'hepan', 'qimen', 'almanac', 'zeri', 'chenggu', 'xiaoliuren', 'star', 'numerology', 'trend', 'fengshui', 'name'],
|
|
110
|
-
description: 'bazi = 四柱八字;ziwei = 紫微斗数;liuyao = 六爻;tarot = 塔罗;meihua = 梅花易数;daliuren = 大六壬;hepan = 合盘(合婚),需同时给 partner;qimen = 奇门遁甲(时家转盘,拆补法);almanac = 黄历(某日宜忌/冲煞/建除/节气);zeri = 择日(某事项在日期区间内逐日打分排序);chenggu = 袁天罡称骨(骨重 + 通行本称骨歌原文 + 白话释义);xiaoliuren = 小六壬(时间或报数起课);star = 星座当日基调;numerology = 生命数字;trend = 人生 K 线(大运/流年走势可视化);fengshui = 风水(八宅命卦/流年飞星/门主灶布局);name =
|
|
110
|
+
enum: ['bazi', 'ziwei', 'liuyao', 'tarot', 'meihua', 'daliuren', 'hepan', 'qimen', 'almanac', 'zeri', 'chenggu', 'xiaoliuren', 'star', 'numerology', 'trend', 'fengshui', 'name', 'convert'],
|
|
111
|
+
description: 'bazi = 四柱八字;ziwei = 紫微斗数;liuyao = 六爻;tarot = 塔罗;meihua = 梅花易数;daliuren = 大六壬;hepan = 合盘(合婚),需同时给 partner;qimen = 奇门遁甲(时家转盘,拆补法);almanac = 黄历(某日宜忌/冲煞/建除/节气);zeri = 择日(某事项在日期区间内逐日打分排序);chenggu = 袁天罡称骨(骨重 + 通行本称骨歌原文 + 白话释义);xiaoliuren = 小六壬(时间或报数起课);star = 星座当日基调;numerology = 生命数字;trend = 人生 K 线(大运/流年走势可视化);fengshui = 风水(八宅命卦/流年飞星/门主灶布局);name = 起名(用字五行评估与候选生成);convert = 公农历互转(solar2lunar 公历转农历 / lunar2solar 农历转公历)。',
|
|
111
112
|
},
|
|
112
113
|
datetime: {
|
|
113
114
|
type: 'string',
|
|
@@ -168,7 +169,7 @@ export function apply(ctx) {
|
|
|
168
169
|
},
|
|
169
170
|
task: {
|
|
170
171
|
type: 'string',
|
|
171
|
-
enum: ['嫁娶', '订婚', '开业', '入宅', '搬家', '动土', '装修', '安葬', '出行', '
|
|
172
|
+
enum: ['嫁娶', '订婚', '领证', '提亲', '收送聘金', '满月酒', '开业', '交易', '投资', '签订合同', '签约', '纳财', '入宅', '搬家', '搬家入宅', '动土', '装修', '装修建造', '安葬', '出行', '旅行', '赴任', '访亲友', '祭祀', '求医', '入学', '试车买车'],
|
|
172
173
|
description: '仅 zeri 使用:要挑的事项。',
|
|
173
174
|
},
|
|
174
175
|
startDate: {
|
|
@@ -184,6 +185,15 @@ export function apply(ctx) {
|
|
|
184
185
|
enum: ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'],
|
|
185
186
|
description: '仅 zeri 使用:当事人属相,用于排除冲煞日(不给则不排除)。',
|
|
186
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:该月是否为闰月。' },
|
|
187
197
|
num1: { type: 'number', description: '仅 xiaoliuren 报数模式:第一个数(1–99)。' },
|
|
188
198
|
num2: { type: 'number', description: '仅 xiaoliuren 报数模式:第二个数(1–99)。' },
|
|
189
199
|
num3: { type: 'number', description: '仅 xiaoliuren 报数模式:第三个数(1–99)。' },
|
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) —
|
|
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."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/zh.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "命理排盘(玄学)· 八字紫微六爻梅花六壬奇门合盘塔罗",
|
|
4
|
-
"description": "
|
|
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.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "命理排盘(玄学 xuanxue)for DeepSeek Harness:
|
|
5
|
+
"description": "命理排盘(玄学 xuanxue)for DeepSeek Harness: eighteen systems — eight chart systems (BaZi four pillars, Zi Wei Dou Shu, LiuYao, MeiHua, Da Liu Ren, Qi Men Dun Jia, compatibility charts, Tarot) plus ten quick references (almanac, solar–lunar conversion, date selection, bone-weight fortune, Xiao Liu Ren, horoscope, numerology, life-curve, feng shui, name analysis); ask-driven interpretation, report layer with evidence and confidence, DST correction for 1986–1991. All computed locally, networking off by default — as an agent tool plus a Web panel.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"玄学",
|
|
8
8
|
"玄学排盘",
|