dsh-metaphysics 0.21.0 → 0.22.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 CHANGED
@@ -2,22 +2,34 @@
2
2
 
3
3
  版本按「一组可感知的改动」发,README 与市场条目描述随能力同步。
4
4
 
5
- ## 0.21.0(已发布)
6
-
7
- 《穷通宝鉴》120 格逐条入库:同一「日主 + 月令」该取什么,书上怎么写的,全都摆出来。
8
-
9
- - 新增 `engine/qiongtong.js`:十天干 × 十二月令共 120 格,每格含用神顺序(首取在前)、原文摘句、出处章号;
10
- - 用神顺序据通行整理表(knowyourbazi 整理表,首格为首选),原文摘句照录 [luckclub.cn](https://www.luckclub.cn/bazi/004/)《穷通宝鉴》每章首段(去掉「徐乐吾曰」评注);
11
- - 数据里的 `quoteStems` 是「原文首段依次提到的天干」,与整理表首取不同处可对照阅读(如正月庚金:表首取戊,原文先举丙);
12
- - 原文全章未见某用神字时(丁酉缺「丙」、癸未缺「壬」)直接写 note「按整理表录入,待以善本核对」,不替它圆场。
13
- - **取用**:调候优先时,寒暖判定定「这一盘缺什么」,穷通宝鉴定「这一格书上取什么」;两者不同向时以调候为先,界面与解释层把两套并列写出,不悄悄合并。
14
- - **评分**:流年天干正落在该格首取时 +0.3,次取 +0.15,理由写明「天干丙正是丑月乙日的首取(穷通宝鉴)」;该干属忌神时不给这笔分。
15
- - **解释层**新增「穷通宝鉴」一节:格(「乙日生于十二月」)+ 用神与首取 + 原文摘句 + 章号;「未纳入」一栏同步改成「已录 120 格,整理表口径、异文处已标 note」。
16
- - **面板**寒暖卡下新增穷通宝鉴块:用神 chips(首取高亮)、原文引句、章号;文本摘要「寒暖:」一行后追加「穷通:十二月乙取丙(首取丙)」。
17
- - 新增 `tools/qiongtong-scrape.mjs`(抓 113 章原文,缓存不入库)与 `tools/qiongtong-build.mjs`(生成 `engine/qiongtong.js`),数据可复现。
18
- - 测试 `test/qiongtong.test.mjs` 31 条:120 格齐全、用神字合法、原文摘句非空、月令月名一致、定值(乙丑取丙、庚寅首取戊/原文先举丙、丁酉与癸未的 note、未知输入返回 null)、1996 寒湿盘接入(detail/评分/解释/面板)。
19
- - 统计:62 个测试文件 / 1745 条断言;client.js 44 模块。
20
-
5
+ ## 0.22.0(已发布)
6
+
7
+ 起名不再只是「未收录」三个字:逐字给出五行、判定与可换字。
8
+
9
+ - 字库 190 → **391 字**(常用名用字为主,按木/火/土/金/水五行分段):丰(火)、秋(金,秋收成熟)、林(木)这类常见字不再掉「未收录」。
10
+ - **逐字判定**:`assessName` 每个字返回五行、释义、性别倾向、来源(`lib` 自建字库 / `user` 你传入的 `charElements` / `none` 未收录)、是否合喜用;未收录的字不猜五行,但会给出**同喜用五行的可换字**(如「秋」不合喜用 → 可换坤(土)、垚(土))。
11
+ - **不替用户下判断**:没给生辰时 `favorable` 返回 `null`(不判合不合),结论分「无生辰 / 全未收录 / 全合 / 部分合 / 全不合」五档,并把统计(几个字、几个已知、几个合喜用、字库共几字)写出来。
12
+ - **候选去同质化**:`generateNames` 三轮选名(新字 + 新五行组合 → 新字 → 放开)× 字库顺序打散 × 两字异行优先,避免「清一色梓桐」。同一盘 8 个候选示例:李炎梓(火木)、李坤桐(土木)、李楠灿(木火)、李楷垚(木土)、李培炫(土火)、李炜城(火土)、李柏松(木木)、李煜烨(火火)。
13
+ - **面板**新增起名卡(`pp.nameHTML`):逐字大字 + 五行 chip + 来源徽标 + 合/不合喜用 + 可换字、八字与喜用一行、结论;生成卡按「名 + 五行 chips + 释义」逐行排,不再是纯文本块。
14
+ - 工具参数新增 `charElements`(`{字: 木|火|土|金|水}`,自定义字五行,未收录字也能参与判定);`name` 的出生信息允许省 `datetime` 用 `year/month/day`。
15
+ - 测试新增 `test/names.test.mjs` 39 条(字库规模与去重、丰秋林逐字判定、未收录字 + 可换字、charElements 生效与非法忽略、无生辰不判、候选全合喜用、面板结构与接线);统计 **63 个测试文件 / 1784 条断言**。
16
+
17
+ ## 0.21.0(已发布)
18
+
19
+ 《穷通宝鉴》120 格逐条入库:同一「日主 + 月令」该取什么,书上怎么写的,全都摆出来。
20
+
21
+ - 新增 `engine/qiongtong.js`:十天干 × 十二月令共 120 格,每格含用神顺序(首取在前)、原文摘句、出处章号;
22
+ - 用神顺序据通行整理表(knowyourbazi 整理表,首格为首选),原文摘句照录 [luckclub.cn](https://www.luckclub.cn/bazi/004/)《穷通宝鉴》每章首段(去掉「徐乐吾曰」评注);
23
+ - 数据里的 `quoteStems` 是「原文首段依次提到的天干」,与整理表首取不同处可对照阅读(如正月庚金:表首取戊,原文先举丙);
24
+ - 原文全章未见某用神字时(丁酉缺「丙」、癸未缺「壬」)直接写 note「按整理表录入,待以善本核对」,不替它圆场。
25
+ - **取用**:调候优先时,寒暖判定定「这一盘缺什么」,穷通宝鉴定「这一格书上取什么」;两者不同向时以调候为先,界面与解释层把两套并列写出,不悄悄合并。
26
+ - **评分**:流年天干正落在该格首取时 +0.3,次取 +0.15,理由写明「天干丙正是丑月乙日的首取(穷通宝鉴)」;该干属忌神时不给这笔分。
27
+ - **解释层**新增「穷通宝鉴」一节:格(「乙日生于十二月」)+ 用神与首取 + 原文摘句 + 章号;「未纳入」一栏同步改成「已录 120 格,整理表口径、异文处已标 note」。
28
+ - **面板**寒暖卡下新增穷通宝鉴块:用神 chips(首取高亮)、原文引句、章号;文本摘要「寒暖:」一行后追加「穷通:十二月乙取丙(首取丙)」。
29
+ - 新增 `tools/qiongtong-scrape.mjs`(抓 113 章原文,缓存不入库)与 `tools/qiongtong-build.mjs`(生成 `engine/qiongtong.js`),数据可复现。
30
+ - 测试 `test/qiongtong.test.mjs` 31 条:120 格齐全、用神字合法、原文摘句非空、月令月名一致、定值(乙丑取丙、庚寅首取戊/原文先举丙、丁酉与癸未的 note、未知输入返回 null)、1996 寒湿盘接入(detail/评分/解释/面板)。
31
+ - 统计:62 个测试文件 / 1745 条断言;client.js 44 模块。
32
+
21
33
  ## 0.20.0(已发布)
22
34
 
23
35
  调候(寒暖燥湿)不再是脚注:从「扶抑为主 + 一句提示」改成「调候优先 + 扶抑校验」的判定层。
package/README.md CHANGED
@@ -20,7 +20,7 @@ Chinese metaphysics (玄学 / xuanxue) for [DeepSeek Harness](https://github.com
20
20
  - **塔罗**:78 张全牌、1/3/5 张牌阵,逐牌牌位义 + 整体解读,体系与逆位口径写明
21
21
  - **速查十件**:黄历(四柱/建除/宜忌/冲煞/节气 + 值日十二神/时辰吉凶/二十八宿/胎神/吉神方位/纳音/六合三合)、农历(公农历互转)、择日(27 类事项、按五组归类、冲属相排除)、称骨(骨重 + 称骨歌原文 + 释义)、
22
22
  小六壬(时间/报数起课)、星座(档案 + 当日基调)、生命数字(生命路径/生日/态度数)、人生 K 线(逐年分与形态)、
23
- 风水(八宅命卦/大游年/流年紫白/门主灶)、起名(喜用五行匹配,未收录如实标注)——口径与边界各自写明
23
+ 风水(八宅命卦/大游年/流年紫白/门主灶)、起名(391 字库、逐字判定与可换字)——口径与边界各自写明
24
24
  - 全部本地计算,不收集数据;结果供文化娱乐参考,不作医疗、投资、法律或生死判断
25
25
 
26
26
  ### 报告化与可核验(0.16 / 0.17 / 0.18 / 0.20 新增)
@@ -98,7 +98,7 @@ Chinese metaphysics (玄学 / xuanxue) for [DeepSeek Harness](https://github.com
98
98
  - **生命数字 `numerology`**:生命路径数 / 生日数 / 态度数,11/22/33 主数保留;与八字口径不同,混问时会说明两套不可互相印证
99
99
  - **人生 K 线 `trend`**:复用八字的旺衰、大运与流年十神,按固定计分表给出 1–100 岁逐年分与最佳/最差年份;面板与独立页画的是**蜡烛图**(实体=相对上一岁的涨跌、影线=±4 分,叠 5/10 年均线并在右缘标末端值、大运条纹带与分界虚线、最高/最低岁标记),图下再给全段均值 / 最好大运 / 最差大运 / 波动幅度,并直接嵌在八字结果底部,与「人生运势曲线」(大运阶梯 + 流年折线)互补:曲线看趋势,K 线看逐年涨跌。旺衰正好落在换档阈值(±0.3)时只提示、不给顺位结论
100
100
  - **风水 `fengshui`**:八宅命卦(1900s/2000s 男女公式、立春界)、大游年四吉四凶、流年九宫飞白、24 山门主灶布局倾向、命宅配调停文案;`scope` 明写**不含**玄空各运盘与现场勘舆
101
- - **起名 `name`**:评估现有名字或按喜用五行生成候选名;241 字自建字库,未收录的字如实标「未收录」;**不做五格剖象**(需康熙字典笔画)与音韵判断
101
+ - **起名 `name`**:391 字自建字库(常用名用字,按五行分段),评估时**逐字**给五行、释义、来源与是否合喜用,未收录的字不猜五行但给**同喜用五行的可换字**(也可用 `charElements` 自行指定);生成候选名按「两字异行优先 + 字库顺序打散 + 三轮去重」避免清一色同字;**不做五格剖象**(需康熙字典笔画)与音韵判断
102
102
 
103
103
  ### 解析与详解(interpret)
104
104
  每个体系的排盘结果下方都会跟一个「解析与详解」模块,帮你把盘面翻译成能看懂、能照着做的事。对话工具里加 `withInterpret: true` 即可一并返回。
@@ -112,7 +112,7 @@ Chinese metaphysics (玄学 / xuanxue) for [DeepSeek Harness](https://github.com
112
112
  - **追问**:工具参数 `ask`、面板与独立页的追问输入框——围绕**已算好的盘**回答「2027 年事业怎么样」「财运如何」这类问题;只取盘面已有字段(流年/大运/宫位/分节),不重排、不猜测;年份超出已排范围或没识别到方面时,明确说找不到并给出可问范围
113
113
  - **八字 × 紫微 交叉验证**:工具参数 `cross`(或面板勾选)会用同一份出生信息再排另一套盘,对事业/财富/感情/身体/节奏五项并列对照,标注「同向 / 有张力 / 互补」;只作对照,不把两套体系折算成同一个分数
114
114
  - **量化口径**:只量化引擎已有数据(十神权重、大运/流年档位、宫位与四化计数),**不换算金额、不给健康诊断**;报告里有「量化口径」分节写明这条边界
115
- - **方法与验证**:独立页内置同页「方法与验证」(体系、128 条卦例对拍、62 个测试文件/1745 条断言、七道闸、口径与已知边界),离线可开
115
+ - **方法与验证**:独立页内置同页「方法与验证」(体系、128 条卦例对拍、63 个测试文件/1784 条断言、七道闸、口径与已知边界),离线可开
116
116
  - **夏令时校正(0.18 新增)**:1986–1991 年中国夏令时期间的钟面时间在排盘前自动减 1 小时(跨日回退),八字/紫微/合盘/验前事/生时校正统一生效;出生证已是真实太阳口径时可用 `dst: false` 关闭
117
117
  - **合婚明细层(0.18 新增)**:合盘新增属相六合/三合/六冲/相害/相刑、天干五合、双向十神、跨盘地支、年命纳音与吉凶象计数分档;只作明细,不改原总分
118
118
  - **晚子时开关**:面板与独立页都能切「23:00 后算次日/当日」;奇门另可切「归当日/归次日」——这是排盘口径,不是结果重算
package/client.js CHANGED
@@ -746,7 +746,7 @@ function resolveAddress(input) {
746
746
 
747
747
  const DETAIL = /(区|县|镇|乡|村|小区|街道|路|号|巷|弄|组|队)/;
748
748
 
749
- const USER_AGENT = 'dsh-metaphysics/0.21.0 (+https://github.com/xuanfu-web/dsh-metaphysics)';
749
+ const USER_AGENT = 'dsh-metaphysics/0.22.0 (+https://github.com/xuanfu-web/dsh-metaphysics)';
750
750
 
751
751
  async function onlineLookup(text, { timeoutMs = 2500 } = {}) {
752
752
  if (typeof fetch !== 'function') return null;
@@ -5881,6 +5881,110 @@ const CHAR_LIB = [
5881
5881
  ['月', '木', '明月', 'f'], ['言', '木', '言语,信', 'n'],
5882
5882
  ['和', '水', '和顺', 'n'], ['安', '土', '安宁', 'n'],
5883
5883
  ['宁', '火', '安宁', 'f'],
5884
+ ['林', '木', '林木成片,茂盛有荫', 'n'], ['森', '木', '众木成林,森然', 'n'],
5885
+ ['枝', '木', '枝条,生发', 'n'], ['果', '木', '果实,有成', 'n'],
5886
+ ['禾', '木', '禾苗,五谷初生', 'n'], ['秀', '木', '禾吐穗,秀美出众', 'n'],
5887
+ ['穗', '木', '谷穗,丰实', 'n'], ['稼', '木', '庄稼,耕作有成', 'm'],
5888
+ ['颖', '木', '禾颖,聪颖', 'n'], ['苗', '木', '苗裔,初生有生机', 'n'],
5889
+ ['菁', '木', '菁华,草木茂盛', 'f'], ['菡', '木', '荷花含苞', 'f'],
5890
+ ['蕴', '木', '蕴积,含而不露', 'f'], ['蕾', '木', '花蕾,待放', 'f'],
5891
+ ['薇', '木', '蔷薇,细而韧', 'f'], ['薏', '木', '薏苡,清润', 'f'],
5892
+ ['菀', '木', '草木茂盛', 'f'], ['荷', '木', '荷花,出淤泥', 'f'],
5893
+ ['莲', '木', '莲花,清直', 'f'], ['菱', '木', '菱角,水生', 'f'],
5894
+ ['苇', '木', '芦苇,柔韧', 'n'], ['荻', '木', '荻草,秋声', 'n'],
5895
+ ['筠', '木', '竹皮,竹之青', 'n'], ['笛', '木', '竹笛,清音', 'n'],
5896
+ ['杉', '木', '杉木,挺拔', 'n'], ['柠', '木', '柠檬,清新', 'f'],
5897
+ ['桢', '木', '桢干,栋梁材', 'm'], ['樾', '木', '树荫,庇下', 'm'],
5898
+ ['柘', '木', '柘木,坚韧', 'n'], ['权', '木', '权衡,执中', 'm'],
5899
+ ['材', '木', '木材,成材', 'm'], ['杭', '木', '苏杭,舟行', 'n'],
5900
+ ['枚', '木', '衔枚,静而进', 'n'], ['梧', '木', '梧桐,栖凤', 'n'],
5901
+ ['竹', '木', '竹,有节而虚心', 'n'], ['简', '木', '简朴,简静', 'n'],
5902
+ ['策', '木', '策谋,鞭策', 'm'], ['筹', '木', '筹算,谋划', 'm'],
5903
+ ['芬', '木', '芬芳', 'f'], ['芳', '木', '芳华', 'f'],
5904
+ ['花', '木', '花,明媚', 'f'], ['菊', '木', '菊花,晚节', 'f'],
5905
+ ['兰', '木', '兰花,幽香', 'f'], ['芝', '木', '芝兰,瑞草', 'f'],
5906
+ ['芹', '木', '芹献,谦诚', 'f'], ['荃', '木', '荃草,香草', 'f'],
5907
+ ['萃', '木', '荟萃,聚合', 'n'], ['蓁', '木', '蓁蓁,草木盛', 'n'],
5908
+ ['荞', '木', '荞麦,实而不华', 'f'], ['莞', '木', '莞尔,浅笑', 'f'],
5909
+ ['萦', '木', '萦绕,绵长', 'f'], ['蔚', '木', '蔚然,文采盛', 'n'],
5910
+ ['芃', '木', '芃芃,草木茂', 'n'], ['芩', '木', '黄芩,草本', 'f'],
5911
+ ['苡', '木', '薏苡,清润', 'f'], ['莱', '木', '莱草,野而秀', 'n'],
5912
+ ['萌', '木', '萌芽,生机', 'n'], ['葆', '木', '永葆,守而不失', 'n'],
5913
+ ['萧', '木', '萧然,清疏', 'n'], ['樟', '木', '樟木,香而久', 'n'],
5914
+ ['樱', '木', '樱花,明丽', 'f'], ['栎', '木', '栎树,坚实', 'n'],
5915
+ ['棹', '木', '舟棹,行水', 'n'], ['楸', '木', '楸树,高直', 'n'],
5916
+ ['槐', '木', '槐树,三公之位', 'n'], ['橙', '木', '橙,明暖', 'n'],
5917
+ ['檀', '木', '檀香,沉静', 'n'],
5918
+ ['丰', '火', '丰盛、丰盈(繁体豐从豆,归火)', 'n'], ['日', '火', '太阳,光明', 'm'],
5919
+ ['阳', '火', '阳光,向阳而生', 'm'], ['光', '火', '光明', 'n'],
5920
+ ['亮', '火', '明亮,爽朗', 'm'], ['明', '火', '光明、明理', 'n'],
5921
+ ['晶', '火', '晶莹,三光', 'f'], ['晴', '火', '晴朗,天开', 'f'],
5922
+ ['夏', '火', '夏天,盛大', 'n'], ['智', '火', '智慧,明达', 'm'],
5923
+ ['卓', '火', '卓越,卓立', 'm'], ['乐', '火', '和乐', 'n'],
5924
+ ['恺', '火', '恺悌,和乐', 'm'], ['恬', '火', '恬静', 'f'],
5925
+ ['甜', '火', '甜美', 'f'], ['亭', '火', '亭亭,端立', 'f'],
5926
+ ['俊', '火', '俊朗,才俊', 'm'], ['丙', '火', '天干丙,阳火', 'm'],
5927
+ ['丁', '火', '天干丁,阴火', 'n'], ['鼎', '火', '鼎立,厚重', 'm'],
5928
+ ['陶', '火', '陶然,自得', 'n'], ['熹', '火', '熹微,晨光', 'n'],
5929
+ ['炀', '火', '火旺,炽盛', 'm'], ['烜', '火', '烜赫,显明', 'm'],
5930
+ ['暻', '火', '日光', 'n'], ['晖', '火', '日晖,光彩', 'n'],
5931
+ ['晔', '火', '光晔,明盛', 'n'], ['旻', '火', '秋天,天高', 'm'],
5932
+ ['晏', '火', '晏然,安和', 'n'], ['晓', '火', '拂晓,天将明', 'f'],
5933
+ ['暄', '火', '温暖,日暖', 'f'], ['昆', '火', '昆山,同也', 'm'],
5934
+ ['伶', '火', '伶俐,聪敏', 'f'],
5935
+ ['山', '土', '山,稳重', 'm'], ['岸', '土', '岸然,独立', 'm'],
5936
+ ['岑', '土', '小山,高而静', 'n'], ['巍', '土', '巍峨,高大', 'm'],
5937
+ ['嵩', '土', '嵩山,高峻', 'm'], ['岭', '土', '山岭,绵延', 'n'],
5938
+ ['奥', '土', '深奥,蕴藉', 'm'], ['宜', '土', '宜然,合度', 'n'],
5939
+ ['容', '土', '包容,容仪', 'n'], ['意', '土', '心意,诚意', 'f'],
5940
+ ['依', '土', '依倚,亲近', 'f'], ['悠', '土', '悠然,从容', 'f'],
5941
+ ['维', '土', '维系,纲维', 'n'], ['纬', '土', '经纬,有条', 'n'],
5942
+ ['永', '土', '永恒,久长', 'n'], ['远', '土', '高远', 'm'],
5943
+ ['辰', '土', '星辰、辰时', 'm'], ['壁', '土', '壁立,端正', 'm'],
5944
+ ['田', '土', '田野,耕获', 'm'], ['由', '土', '由来,自得', 'n'],
5945
+ ['画', '土', '图画,文采', 'f'], ['延', '土', '延展,绵长', 'm'],
5946
+ ['建', '土', '建立,树也', 'm'], ['音', '土', '音声,和鸣', 'f'],
5947
+ ['韵', '土', '韵致,余响', 'f'], ['玮', '土', '美玉,珍奇', 'm'],
5948
+ ['雍', '土', '雍容,和穆', 'm'], ['懿', '土', '懿德,美善', 'f'],
5949
+ ['金', '金', '金,坚而贵', 'm'], ['秋', '金', '秋收、成熟(秋属金,肃而收)', 'n'],
5950
+ ['书', '金', '书卷,文墨', 'n'], ['舒', '金', '舒展,从容', 'n'],
5951
+ ['善', '金', '善良,善成', 'n'], ['信', '金', '诚信,符信', 'm'],
5952
+ ['修', '金', '修远,修身', 'm'], ['素', '金', '素雅,本色', 'f'],
5953
+ ['静', '金', '安静,沉静', 'f'], ['心', '金', '心志,中藏', 'f'],
5954
+ ['新', '金', '新意,日新', 'n'], ['正', '金', '正直,端正', 'm'],
5955
+ ['世', '金', '世代,绵延', 'm'], ['少', '金', '少年,少壮', 'm'],
5956
+ ['西', '金', '西方,金位', 'n'], ['白', '金', '洁白,素净', 'n'],
5957
+ ['辛', '金', '天干辛,阴金', 'n'], ['成', '金', '成器,成事', 'm'],
5958
+ ['利', '金', '利落,锋利', 'm'], ['剑', '金', '剑,刚锐', 'm'],
5959
+ ['刚', '金', '刚强,不屈', 'm'], ['则', '金', '法则,有度', 'm'],
5960
+ ['初', '金', '初心,开端', 'n'], ['硕', '金', '硕大,学殖', 'm'],
5961
+ ['尚', '金', '崇尚,尚贤', 'n'], ['臣', '金', '臣,佐事', 'm'],
5962
+ ['川', '金', '川流,通达', 'n'], ['舟', '金', '舟行,济渡', 'n'],
5963
+ ['州', '金', '州,聚落', 'n'], ['祖', '金', '祖德,源远', 'm'],
5964
+ ['祥', '金', '吉祥,祥瑞', 'n'], ['禄', '金', '福禄,俸给', 'm'],
5965
+ ['禧', '金', '禧庆,福', 'n'], ['珍', '金', '珍宝,珍重', 'f'],
5966
+ ['宣', '金', '宣明,布达', 'n'], ['序', '金', '秩序,庠序', 'n'],
5967
+ ['谦', '金', '谦逊,有终', 'm'], ['赞', '金', '赞美,佐成', 'm'],
5968
+ ['超', '金', '超越,越过', 'm'], ['锴', '金', '精铁,坚刚', 'm'],
5969
+ ['水', '水', '水,润下', 'n'], ['冰', '水', '冰清,澄澈', 'f'],
5970
+ ['洁', '水', '洁净,洁身', 'f'], ['浩', '水', '浩大,广远', 'm'],
5971
+ ['瀚', '水', '浩瀚,无涯', 'm'], ['渊', '水', '渊深,有本', 'm'],
5972
+ ['澜', '水', '波澜,壮阔', 'n'], ['潮', '水', '潮涌,有信', 'n'],
5973
+ ['溪', '水', '溪流,清浅', 'f'], ['湘', '水', '湘水,清深', 'f'],
5974
+ ['渝', '水', '渝水,守而不变', 'n'], ['深', '水', '深厚,深藏', 'm'],
5975
+ ['湛', '水', '湛然,清深', 'm'], ['汇', '水', '汇聚,会归', 'n'],
5976
+ ['洲', '水', '洲渚,水中地', 'n'], ['湾', '水', '水湾,曲处', 'f'],
5977
+ ['云', '水', '云行,舒卷', 'n'], ['风', '水', '风雅,流动', 'n'],
5978
+ ['北', '水', '北方,水位', 'n'], ['冬', '水', '冬藏,静敛', 'f'],
5979
+ ['玄', '水', '玄远,幽深', 'n'], ['子', '水', '子,初生', 'm'],
5980
+ ['平', '水', '平和,坦易', 'n'], ['方', '水', '方正,有隅', 'n'],
5981
+ ['帆', '水', '风帆,顺行', 'n'], ['航', '水', '航行,济远', 'm'],
5982
+ ['敏', '水', '敏思,捷悟', 'f'], ['慧', '水', '慧心,明彻', 'f'],
5983
+ ['惠', '水', '惠泽,施与', 'f'], ['霈', '水', '霈雨,丰沛', 'm'],
5984
+ ['灏', '水', '灏气,广大', 'm'], ['湄', '水', '水湄,岸边', 'f'],
5985
+ ['滨', '水', '水滨,近水', 'n'], ['洛', '水', '洛水,清流', 'n'],
5986
+ ['津', '水', '津渡,要处', 'n'], ['泊', '水', '淡泊,自守', 'm'],
5987
+ ['沧', '水', '沧海,苍茫', 'm'], ['浦', '水', '浦,水滨', 'n'],
5884
5988
  ];
5885
5989
 
5886
5990
  const EL_INDEX = new Map();
@@ -5888,6 +5992,22 @@ for (const c of CHAR_LIB) {
5888
5992
  if (!EL_INDEX.has(c[0])) EL_INDEX.set(c[0], { c: c[0], el: c[1], meaning: c[2], g: c[3], order: EL_INDEX.size });
5889
5993
  }
5890
5994
 
5995
+ function userElement(input, ch) {
5996
+ const map = input && input.charElements;
5997
+ if (!map || typeof map !== 'object') return null;
5998
+ const v = map[ch];
5999
+ return ALL.includes(v) ? v : null;
6000
+ }
6001
+
6002
+ function suggestFor(element, genderPref, exclude, count = 3) {
6003
+ const pool = CHAR_LIB.filter((c) => c[1] === element && !exclude.has(c[0]));
6004
+ pool.sort((a, b) => {
6005
+ const fit = (x) => (x[3] === genderPref || x[3] === 'n' ? 1 : 0);
6006
+ return fit(b) - fit(a);
6007
+ });
6008
+ return pool.slice(0, count).map((c) => ({ char: c[0], element: c[1], meaning: c[2] }));
6009
+ }
6010
+
5891
6011
  const KIND_LABEL = { m: '男', f: '女', n: '中' };
5892
6012
 
5893
6013
  function favorableElements(strength) {
@@ -5941,23 +6061,44 @@ function assessName(input) {
5941
6061
  baziNote = { dayMaster: r.dayMaster, solarNote: r.solarTime ? r.solarTime.note : '' };
5942
6062
  }
5943
6063
 
6064
+ const genderPref = input.gender === 'female' ? 'f' : 'm';
6065
+ const taken = new Set([surname, ...given]);
6066
+ const favPool = favorable.list.length ? favorable.list : ALL.slice();
5944
6067
  const chars = [...given].map((ch) => {
5945
6068
  const info = charInfo(ch);
5946
- const inFav = info ? favorable.list.includes(info.el) : null;
6069
+ const given = userElement(input, ch);
6070
+ if (info) {
6071
+ return {
6072
+ char: ch, element: info.el, meaning: info.meaning,
6073
+ genderHint: KIND_LABEL[info.g], favorable: hasBirth ? favorable.list.includes(info.el) : null,
6074
+ source: 'lib', note: null,
6075
+ };
6076
+ }
6077
+ if (given) {
6078
+ return {
6079
+ char: ch, element: given, meaning: '字库未收录;五行按你指定的「' + given + '」计',
6080
+ genderHint: null, favorable: hasBirth ? favorable.list.includes(given) : null,
6081
+ source: 'user', note: '此字五行由调用方指定,不是字库推断',
6082
+ };
6083
+ }
5947
6084
  return {
5948
- char: ch,
5949
- element: info ? info.el : '未收录',
5950
- meaning: info ? info.meaning : '字库未收录,未推断五行',
5951
- genderHint: info ? KIND_LABEL[info.g] : null,
5952
- favorable: inFav,
6085
+ char: ch, element: '未收录', meaning: '字库未收录,未推断五行(不猜)',
6086
+ genderHint: null, favorable: null, source: 'none',
6087
+ note: hasBirth ? '若想贴合命局,可换用下面的同喜用字' : '字库未收录:给出生辰后可以看同喜用的替换字',
6088
+ suggest: hasBirth
6089
+ ? favPool.flatMap((el) => suggestFor(el, genderPref, taken, 2))
6090
+ : [],
5953
6091
  };
5954
6092
  });
5955
- const known = chars.filter((c) => c.element !== '未收录').length;
6093
+ const known = chars.filter((c) => c.source === 'lib').length;
6094
+ const unknown = chars.filter((c) => c.source === 'none').length;
5956
6095
  const favCount = chars.filter((c) => c.favorable === true).length;
6096
+ const judged = chars.length - unknown;
5957
6097
  let verdict;
5958
6098
  if (!hasBirth) verdict = '只做了字义与五行归类;给出生年月日才能判断用字是否合喜用。';
5959
- else if (favCount === chars.length && chars.length > 0) verdict = `用字都落在喜用(${favorable.list.join('、')})上,与命局方向一致。`;
5960
- else if (favCount > 0) verdict = `部分用字合喜用(${favCount}/${chars.length}),其余可再斟酌;喜用为 ${favorable.list.join('、')}。`;
6099
+ else if (unknown === chars.length) verdict = `两字都不在字库里,没法判断合不合喜用(喜用为 ${favorable.list.join('、')})。下面给了可替换的常用字,或把你自己认定的五行传进来。`;
6100
+ else if (favCount === judged && judged > 0) verdict = `用字都落在喜用(${favorable.list.join('、')})上,与命局方向一致。`;
6101
+ else if (favCount > 0) verdict = `部分用字合喜用(${favCount}/${judged}),其余可再斟酌;喜用为 ${favorable.list.join('、')}。`;
5961
6102
  else verdict = `用字未落在喜用(${favorable.list.join('、')})上;不必然是坏名,但若想贴合命局可换字再看。`;
5962
6103
 
5963
6104
  return {
@@ -5975,10 +6116,10 @@ function assessName(input) {
5975
6116
  },
5976
6117
  } : {}),
5977
6118
  chars,
5978
- stats: { chars: chars.length, known, favorableCount: favCount },
6119
+ stats: { chars: chars.length, known, unknown, favorableCount: favCount, libSize: CHAR_LIB.length },
5979
6120
  verdict,
5980
6121
  notes: [
5981
- '字之五行按通行字义/偏旁归类,自建字库有限:未收录的字不猜五行,如实标注。',
6122
+ `字之五行按通行字义/偏旁归类,自建字库共 ${CHAR_LIB.length} 字(常用名用字为主);未收录的字不猜五行,如实标注,「用户指定」是你传入的归类。`,
5982
6123
  '不做五格剖象(需康熙字典笔画),也不做音韵格律判断——谐音、拗口请自己读三遍或用方言读一遍。',
5983
6124
  '起名只做用字参考,不替父母做决定。',
5984
6125
  ],
@@ -6025,19 +6166,39 @@ function generateNames(input) {
6025
6166
  elements: [a[1], b[1]],
6026
6167
  allFavorable: fav.list.includes(a[1]) && fav.list.includes(b[1]),
6027
6168
  genderScore: gScore,
6028
- order: i * 1000 + j,
6169
+ order: (i * 7 + j * 13) % 9973,
6029
6170
  });
6030
6171
  }
6031
6172
  }
6032
- scored.sort((x, y) => (y.allFavorable - x.allFavorable) || (y.genderScore - x.genderScore) || (x.order - y.order));
6173
+ const mixed = (c) => (c.elements[0] !== c.elements[1] ? 1 : 0);
6174
+ scored.sort((x, y) => (y.allFavorable - x.allFavorable) || (mixed(y) - mixed(x)) || (y.genderScore - x.genderScore) || (x.order - y.order));
6033
6175
  const out = [];
6034
- const used = new Set();
6035
- for (const cand of scored) {
6036
- if (out.length >= limit) break;
6176
+ const usedNames = new Set();
6177
+ const usedChars = new Set([surname]);
6178
+ const usedPairs = new Set();
6179
+ const take = (cand, strict, freshPair) => {
6037
6180
  const key = [...cand.name].sort().join('');
6038
- if (used.has(key)) continue;
6039
- used.add(key);
6181
+ if (usedNames.has(key)) return false;
6182
+ if (strict && cand.chars.some((x) => usedChars.has(x.char))) return false;
6183
+ const pair = cand.elements.join('');
6184
+ if (freshPair && usedPairs.has(pair)) return false;
6185
+ usedNames.add(key);
6186
+ usedPairs.add(pair);
6187
+ cand.chars.forEach((x) => usedChars.add(x.char));
6040
6188
  out.push({ rank: out.length + 1, name: surname + cand.name, given: cand.name, chars: cand.chars });
6189
+ return true;
6190
+ };
6191
+ for (const cand of scored) {
6192
+ if (out.length >= limit) break;
6193
+ take(cand, true, true);
6194
+ }
6195
+ for (const cand of scored) {
6196
+ if (out.length >= limit) break;
6197
+ take(cand, true, false);
6198
+ }
6199
+ for (const cand of scored) {
6200
+ if (out.length >= limit) break;
6201
+ take(cand, false, false);
6041
6202
  }
6042
6203
  return {
6043
6204
  system: 'name',
@@ -6047,7 +6208,7 @@ function generateNames(input) {
6047
6208
  bazi: { dayMaster: r.dayMaster, strength, favorable: fav.list, basis: fav.basis },
6048
6209
  candidates: out,
6049
6210
  notes: [
6050
- `字库共 ${CHAR_LIB.length} 字,只在喜用五行(${fav.list.join('、')})里选字;未覆盖的生僻好字可手工评估。`,
6211
+ `字库共 ${CHAR_LIB.length} 字,只在喜用五行(${fav.list.join('、')})里选字;未覆盖的生僻好字可用 charElements 指定五行后评估。`,
6051
6212
  '候选按合喜用与性别倾向确定性排序,不是「吉名」判定;音韵与方言谐音请自行读念检查。',
6052
6213
  '不做五格剖象(需康熙字典笔画)。',
6053
6214
  ],
@@ -10781,12 +10942,21 @@ function computeRaw(args = {}) {
10781
10942
  }
10782
10943
  if (system === 'name') {
10783
10944
  const action = args.action === 'generate' ? 'generate' : 'assess';
10784
- const birth = args.datetime ? parseDateTime(args.datetime) : {};
10945
+ const birth = args.datetime
10946
+ ? parseDateTime(args.datetime)
10947
+ : (Number.isInteger(args.year) && Number.isInteger(args.month) && Number.isInteger(args.day)
10948
+ ? {
10949
+ year: args.year, month: args.month, day: args.day,
10950
+ ...(Number.isInteger(args.hour) ? { hour: args.hour } : {}),
10951
+ ...(Number.isInteger(args.minute) ? { minute: args.minute } : {}),
10952
+ }
10953
+ : {});
10785
10954
  const result = buildName({
10786
10955
  action,
10787
10956
  surname: args.surname,
10788
10957
  givenName: args.givenName,
10789
10958
  limit: args.limit,
10959
+ charElements: args.charElements && typeof args.charElements === 'object' ? args.charElements : undefined,
10790
10960
  ...birth,
10791
10961
  ...(args.gender === 'male' || args.gender === 'female' ? { gender: args.gender } : {}),
10792
10962
  ...(args.datetime ? {
@@ -10954,9 +11124,18 @@ function nameText(r) {
10954
11124
  ...r.notes.map((n) => `※ ${n}`),
10955
11125
  ].join('\n');
10956
11126
  }
11127
+ const srcLabel = (c) => (c.source === 'lib' ? '字库' : c.source === 'user' ? '用户指定' : '未收录');
11128
+ const charLine = (c) => {
11129
+ const el = c.element === '未收录' ? '未收录(不猜五行)' : `${c.element}(${srcLabel(c)})`;
11130
+ const fit = c.favorable === true ? '合喜用' : c.favorable === false ? '不合喜用' : '不判';
11131
+ const sug = c.suggest && c.suggest.length
11132
+ ? ` 可换:${c.suggest.map((x) => `${x.char}(${x.element})`).join('、')}`
11133
+ : '';
11134
+ return `· ${c.char}:${el}|${fit}|${c.meaning}${sug}`;
11135
+ };
10957
11136
  return [
10958
11137
  `【名字评估】${r.fullName}`,
10959
- ...r.chars.map((c) => `· ${c.char}:五行 ${c.element}${c.element !== '未收录' ? `(喜用${c.favorable ? '中' : '外'})` : ''},${c.meaning}`),
11138
+ ...r.chars.map(charLine),
10960
11139
  r.bazi ? `【八字】日主 ${r.bazi.dayMaster && r.bazi.dayMaster.stem ? `${r.bazi.dayMaster.stem}(${r.bazi.dayMaster.element})` : r.bazi.dayMaster},旺衰 ${r.bazi.strength.level}(${r.bazi.strength.score}),${r.bazi.basis}` : '',
10961
11140
  `【结论】${r.verdict}`,
10962
11141
  ...r.notes.map((n) => `※ ${n}`),
@@ -11542,7 +11721,32 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
11542
11721
  .mp-qt-q{margin-top:6px;font-size:12.5px;line-height:1.8;color:var(--ink2);font-family:var(--fx)}
11543
11722
  .mp-qt-q span{display:block;font-size:11px;color:var(--ink3);font-family:var(--sans);margin-top:2px}
11544
11723
  @media print{.mp-cli{break-inside:avoid}}
11545
- @media print{.mp-cli{break-inside:avoid}}
11724
+ .mp-nm{margin:12px 16px;border:1px solid var(--line);border-radius:8px;background:var(--card);padding:12px 14px;font-family:system-ui,sans-serif}
11725
+ .mp-nm-h{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;border-bottom:1px solid var(--hair);padding-bottom:8px;margin-bottom:10px}
11726
+ .mp-nm-h b{font-size:17px;color:var(--ink);font-weight:700}
11727
+ .mp-nm-h i{font-style:normal;font-size:12px;color:var(--muted)}
11728
+ .mp-nm-row{display:grid;grid-template-columns:52px 1fr;gap:10px;align-items:start;padding:8px 0;border-bottom:1px dashed var(--hair)}
11729
+ .mp-nm-row:last-of-type{border-bottom:0}
11730
+ .mp-nm-ch{font-size:30px;line-height:1.1;font-family:var(--fx);text-align:center;color:var(--ink)}
11731
+ .mp-nm-b{min-width:0}
11732
+ .mp-nm-t{display:flex;align-items:center;gap:7px;flex-wrap:wrap;font-size:12.5px;color:var(--ink2)}
11733
+ .mp-nm-el{font-size:11.5px;border:1px solid currentColor;border-radius:999px;padding:0 7px;line-height:1.7}
11734
+ .mp-nm-fit{font-size:11px;border-radius:999px;padding:0 7px;line-height:1.7;border:1px solid var(--line);color:var(--muted)}
11735
+ .mp-nm-fit.ok{color:var(--lu);border-color:var(--lu)}
11736
+ .mp-nm-fit.no{color:var(--ji);border-color:var(--ji)}
11737
+ .mp-nm-m{margin-top:3px;font-size:12.5px;line-height:1.75;color:var(--ink2)}
11738
+ .mp-nm-sug{margin-top:4px;font-size:12px;color:var(--muted)}
11739
+ .mp-nm-sug b{font-weight:600;color:var(--ink2);margin-right:4px}
11740
+ .mp-nm-sug span{white-space:nowrap;margin-right:7px}
11741
+ .mp-nm-verd{margin-top:10px;padding:8px 10px;border-left:2px solid var(--quan);background:var(--band);font-size:12.5px;line-height:1.8;color:var(--ink2)}
11742
+ .mp-nm-note{margin-top:8px;font-size:11.5px;line-height:1.8;color:var(--faint)}
11743
+ .mp-nm-cand{margin-top:6px;border-top:1px solid var(--hair)}
11744
+ .mp-nm-els{display:flex;gap:4px;align-items:center}
11745
+ .mp-nm-c{display:grid;grid-template-columns:104px max-content minmax(0,1fr);gap:9px;align-items:center;padding:7px 0;border-bottom:1px dashed var(--hair);font-size:13.5px;color:var(--ink)}
11746
+ .mp-nm-c:last-child{border-bottom:0}
11747
+ .mp-nm-c b{font-family:var(--fx);font-size:16.5px;font-weight:600;white-space:nowrap;letter-spacing:.5px}
11748
+ .mp-nm-c em{font-style:normal;font-size:11.5px;line-height:1.7;color:var(--muted);font-family:var(--sans)}
11749
+ @media print{.mp-nm{break-inside:avoid}}
11546
11750
  .mp-quick-pre{margin:0;white-space:pre-wrap;word-break:break-word;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.9;color:var(--ink2)}
11547
11751
  .mp-al{margin:12px 16px;border:1px solid var(--line);border-radius:8px;background:var(--card);padding:12px 14px;font-family:system-ui,sans-serif}
11548
11752
  .mp-al-h{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;border-bottom:1px solid var(--hair);padding-bottom:8px;margin-bottom:9px}
@@ -12651,6 +12855,47 @@ return { interpret, DIRECTIONS, DIRECTION_DEFAULT, BRIGHTNESS, flowOf, geocodeAd
12651
12855
  </section>`;
12652
12856
  };
12653
12857
 
12858
+ pp.nameHTML = function (r) {
12859
+ if (!r) return '';
12860
+ const ELC = { 木: 'wood', 火: 'fire', 土: 'earth', 金: 'metal', 水: 'water' };
12861
+ const elChip = (e) => (e === '未收录'
12862
+ ? '<span class="mp-nm-el">未收录</span>'
12863
+ : `<span class="mp-nm-el wx-${ELC[e] || 'earth'}">${esc(e)}</span>`);
12864
+ const head = (title, sub) => `<div class="mp-nm-h"><b>${esc(title)}</b>${sub ? `<i>${esc(sub)}</i>` : ''}</div>`;
12865
+ if (r.action === 'generate') {
12866
+ const fav = r.bazi && r.bazi.favorable ? r.bazi.favorable.join('、') : '';
12867
+ const cands = (r.candidates || []).map((c) => `<div class="mp-nm-c"><b>${esc(c.name)}</b><span class="mp-nm-els">${c.chars.map((x) => elChip(x.element)).join('')}</span><em>${esc(c.chars.map((x) => x.char + '·' + x.meaning).join(' '))}</em></div>`).join('');
12868
+ return `<section class="mp-nm" aria-label="候选名">
12869
+ ${head('候选名', `姓 ${r.surname}(${r.gender})${fav ? ` 喜用 ${fav}` : ''}`)}
12870
+ <div class="mp-nm-cand">${cands}</div>
12871
+ <div class="mp-nm-note">${(r.notes || []).map((n) => '※ ' + esc(n)).join('<br>')}</div>
12872
+ </section>`;
12873
+ }
12874
+ const rows = (r.chars || []).map((c) => {
12875
+ const fit = c.favorable === true ? '<span class="mp-nm-fit ok">合喜用</span>'
12876
+ : c.favorable === false ? '<span class="mp-nm-fit no">不合喜用</span>'
12877
+ : '<span class="mp-nm-fit">不判</span>';
12878
+ const src = c.source === 'user' ? '用户指定' : c.source === 'lib' ? '字库' : '未收录';
12879
+ const sug = c.suggest && c.suggest.length
12880
+ ? `<div class="mp-nm-sug"><b>可换</b>${c.suggest.map((x) => `<span class="wx-${ELC[x.element] || 'earth'}">${esc(x.char)}(${esc(x.element)})</span>`).join('')}</div>`
12881
+ : '';
12882
+ return `<div class="mp-nm-row"><div class="mp-nm-ch">${esc(c.char)}</div>
12883
+ <div class="mp-nm-b"><div class="mp-nm-t">${elChip(c.element)}<span>${esc(src)}</span>${fit}</div>
12884
+ <div class="mp-nm-m">${esc(c.meaning)}</div>${sug}</div></div>`;
12885
+ }).join('');
12886
+ const bz = r.bazi
12887
+ ? `<div class="mp-nm-m">八字:${esc(r.bazi.dayMaster && r.bazi.dayMaster.stem ? `${r.bazi.dayMaster.stem}(${r.bazi.dayMaster.element})` : String(r.bazi.dayMaster || ''))} ${esc(r.bazi.strength ? `${r.bazi.strength.level}(${r.bazi.strength.score})` : '')} 喜用 ${esc((r.bazi.favorable || []).join('、'))}</div>
12888
+ <div class="mp-nm-m">${esc(r.bazi.basis || '')}</div>`
12889
+ : '';
12890
+ return `<section class="mp-nm" aria-label="名字评估">
12891
+ ${head(r.fullName || '', `字库 ${r.stats && r.stats.libSize ? r.stats.libSize : ''} 字${r.stats && r.stats.unknown ? ` 未收录 ${r.stats.unknown}` : ''}`)}
12892
+ ${rows}
12893
+ ${bz}
12894
+ <div class="mp-nm-verd">${esc(r.verdict || '')}</div>
12895
+ <div class="mp-nm-note">${(r.notes || []).map((n) => '※ ' + esc(n)).join('<br>')}</div>
12896
+ </section>`;
12897
+ };
12898
+
12654
12899
  pp.baziHTML = function (r) {
12655
12900
  const cols = [['year', '年柱'], ['month', '月柱'], ['day', '日柱'], ['hour', '时柱']];
12656
12901
  const SHORT = { year: '年', month: '月', day: '日', hour: '时' };
@@ -13863,6 +14108,7 @@ function App() {
13863
14108
  : result.kind === 'chenggu' ? PP.chengguHTML(result.r)
13864
14109
  : result.kind === 'almanac' ? PP.almanacHTML(result.r)
13865
14110
  : result.kind === 'trend' ? PP.trendHTML(result.r)
14111
+ : result.kind === 'name' ? PP.nameHTML(result.r)
13866
14112
  : PP.quickHTML(result.r),
13867
14113
  result.it,
13868
14114
  { folded: defaultFolded() },
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.21.0 (+https://github.com/xuanfu-web/dsh-metaphysics)';
146
+ const USER_AGENT = 'dsh-metaphysics/0.22.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
@@ -703,12 +703,21 @@ function computeRaw(args = {}) {
703
703
  }
704
704
  if (system === 'name') {
705
705
  const action = args.action === 'generate' ? 'generate' : 'assess';
706
- const birth = args.datetime ? parseDateTime(args.datetime) : {};
706
+ const birth = args.datetime
707
+ ? parseDateTime(args.datetime)
708
+ : (Number.isInteger(args.year) && Number.isInteger(args.month) && Number.isInteger(args.day)
709
+ ? {
710
+ year: args.year, month: args.month, day: args.day,
711
+ ...(Number.isInteger(args.hour) ? { hour: args.hour } : {}),
712
+ ...(Number.isInteger(args.minute) ? { minute: args.minute } : {}),
713
+ }
714
+ : {});
707
715
  const result = buildName({
708
716
  action,
709
717
  surname: args.surname,
710
718
  givenName: args.givenName,
711
719
  limit: args.limit,
720
+ charElements: args.charElements && typeof args.charElements === 'object' ? args.charElements : undefined,
712
721
  ...birth,
713
722
  ...(args.gender === 'male' || args.gender === 'female' ? { gender: args.gender } : {}),
714
723
  ...(args.datetime ? {
@@ -886,9 +895,18 @@ function nameText(r) {
886
895
  ...r.notes.map((n) => `※ ${n}`),
887
896
  ].join('\n');
888
897
  }
898
+ const srcLabel = (c) => (c.source === 'lib' ? '字库' : c.source === 'user' ? '用户指定' : '未收录');
899
+ const charLine = (c) => {
900
+ const el = c.element === '未收录' ? '未收录(不猜五行)' : `${c.element}(${srcLabel(c)})`;
901
+ const fit = c.favorable === true ? '合喜用' : c.favorable === false ? '不合喜用' : '不判';
902
+ const sug = c.suggest && c.suggest.length
903
+ ? ` 可换:${c.suggest.map((x) => `${x.char}(${x.element})`).join('、')}`
904
+ : '';
905
+ return `· ${c.char}:${el}|${fit}|${c.meaning}${sug}`;
906
+ };
889
907
  return [
890
908
  `【名字评估】${r.fullName}`,
891
- ...r.chars.map((c) => `· ${c.char}:五行 ${c.element}${c.element !== '未收录' ? `(喜用${c.favorable ? '中' : '外'})` : ''},${c.meaning}`),
909
+ ...r.chars.map(charLine),
892
910
  r.bazi ? `【八字】日主 ${r.bazi.dayMaster && r.bazi.dayMaster.stem ? `${r.bazi.dayMaster.stem}(${r.bazi.dayMaster.element})` : r.bazi.dayMaster},旺衰 ${r.bazi.strength.level}(${r.bazi.strength.score}),${r.bazi.basis}` : '',
893
911
  `【结论】${r.verdict}`,
894
912
  ...r.notes.map((n) => `※ ${n}`),
package/engine/name.js CHANGED
@@ -116,6 +116,115 @@ export const CHAR_LIB = [
116
116
  ['月', '木', '明月', 'f'], ['言', '木', '言语,信', 'n'],
117
117
  ['和', '水', '和顺', 'n'], ['安', '土', '安宁', 'n'],
118
118
  ['宁', '火', '安宁', 'f'],
119
+ // ── 扩充:木 ──
120
+ ['林', '木', '林木成片,茂盛有荫', 'n'], ['森', '木', '众木成林,森然', 'n'],
121
+ ['枝', '木', '枝条,生发', 'n'], ['果', '木', '果实,有成', 'n'],
122
+ ['禾', '木', '禾苗,五谷初生', 'n'], ['秀', '木', '禾吐穗,秀美出众', 'n'],
123
+ ['穗', '木', '谷穗,丰实', 'n'], ['稼', '木', '庄稼,耕作有成', 'm'],
124
+ ['颖', '木', '禾颖,聪颖', 'n'], ['苗', '木', '苗裔,初生有生机', 'n'],
125
+ ['菁', '木', '菁华,草木茂盛', 'f'], ['菡', '木', '荷花含苞', 'f'],
126
+ ['蕴', '木', '蕴积,含而不露', 'f'], ['蕾', '木', '花蕾,待放', 'f'],
127
+ ['薇', '木', '蔷薇,细而韧', 'f'], ['薏', '木', '薏苡,清润', 'f'],
128
+ ['菀', '木', '草木茂盛', 'f'], ['荷', '木', '荷花,出淤泥', 'f'],
129
+ ['莲', '木', '莲花,清直', 'f'], ['菱', '木', '菱角,水生', 'f'],
130
+ ['苇', '木', '芦苇,柔韧', 'n'], ['荻', '木', '荻草,秋声', 'n'],
131
+ ['筠', '木', '竹皮,竹之青', 'n'], ['笛', '木', '竹笛,清音', 'n'],
132
+ ['杉', '木', '杉木,挺拔', 'n'], ['柠', '木', '柠檬,清新', 'f'],
133
+ ['桢', '木', '桢干,栋梁材', 'm'], ['樾', '木', '树荫,庇下', 'm'],
134
+ ['柘', '木', '柘木,坚韧', 'n'], ['权', '木', '权衡,执中', 'm'],
135
+ ['材', '木', '木材,成材', 'm'], ['杭', '木', '苏杭,舟行', 'n'],
136
+ ['枚', '木', '衔枚,静而进', 'n'], ['梧', '木', '梧桐,栖凤', 'n'],
137
+ ['竹', '木', '竹,有节而虚心', 'n'], ['简', '木', '简朴,简静', 'n'],
138
+ ['策', '木', '策谋,鞭策', 'm'], ['筹', '木', '筹算,谋划', 'm'],
139
+ ['芬', '木', '芬芳', 'f'], ['芳', '木', '芳华', 'f'],
140
+ ['花', '木', '花,明媚', 'f'], ['菊', '木', '菊花,晚节', 'f'],
141
+ ['兰', '木', '兰花,幽香', 'f'], ['芝', '木', '芝兰,瑞草', 'f'],
142
+ ['芹', '木', '芹献,谦诚', 'f'], ['荃', '木', '荃草,香草', 'f'],
143
+ ['萃', '木', '荟萃,聚合', 'n'], ['蓁', '木', '蓁蓁,草木盛', 'n'],
144
+ ['荞', '木', '荞麦,实而不华', 'f'], ['莞', '木', '莞尔,浅笑', 'f'],
145
+ ['萦', '木', '萦绕,绵长', 'f'], ['蔚', '木', '蔚然,文采盛', 'n'],
146
+ ['芃', '木', '芃芃,草木茂', 'n'], ['芩', '木', '黄芩,草本', 'f'],
147
+ ['苡', '木', '薏苡,清润', 'f'], ['莱', '木', '莱草,野而秀', 'n'],
148
+ ['萌', '木', '萌芽,生机', 'n'], ['葆', '木', '永葆,守而不失', 'n'],
149
+ ['萧', '木', '萧然,清疏', 'n'], ['樟', '木', '樟木,香而久', 'n'],
150
+ ['樱', '木', '樱花,明丽', 'f'], ['栎', '木', '栎树,坚实', 'n'],
151
+ ['棹', '木', '舟棹,行水', 'n'], ['楸', '木', '楸树,高直', 'n'],
152
+ ['槐', '木', '槐树,三公之位', 'n'], ['橙', '木', '橙,明暖', 'n'],
153
+ ['檀', '木', '檀香,沉静', 'n'],
154
+ // ── 扩充:火 ──
155
+ ['丰', '火', '丰盛、丰盈(繁体豐从豆,归火)', 'n'], ['日', '火', '太阳,光明', 'm'],
156
+ ['阳', '火', '阳光,向阳而生', 'm'], ['光', '火', '光明', 'n'],
157
+ ['亮', '火', '明亮,爽朗', 'm'], ['明', '火', '光明、明理', 'n'],
158
+ ['晶', '火', '晶莹,三光', 'f'], ['晴', '火', '晴朗,天开', 'f'],
159
+ ['夏', '火', '夏天,盛大', 'n'], ['智', '火', '智慧,明达', 'm'],
160
+ ['卓', '火', '卓越,卓立', 'm'], ['乐', '火', '和乐', 'n'],
161
+ ['恺', '火', '恺悌,和乐', 'm'], ['恬', '火', '恬静', 'f'],
162
+ ['甜', '火', '甜美', 'f'], ['亭', '火', '亭亭,端立', 'f'],
163
+ ['俊', '火', '俊朗,才俊', 'm'], ['丙', '火', '天干丙,阳火', 'm'],
164
+ ['丁', '火', '天干丁,阴火', 'n'], ['鼎', '火', '鼎立,厚重', 'm'],
165
+ ['陶', '火', '陶然,自得', 'n'], ['熹', '火', '熹微,晨光', 'n'],
166
+ ['炀', '火', '火旺,炽盛', 'm'], ['烜', '火', '烜赫,显明', 'm'],
167
+ ['暻', '火', '日光', 'n'], ['晖', '火', '日晖,光彩', 'n'],
168
+ ['晔', '火', '光晔,明盛', 'n'], ['旻', '火', '秋天,天高', 'm'],
169
+ ['晏', '火', '晏然,安和', 'n'], ['晓', '火', '拂晓,天将明', 'f'],
170
+ ['暄', '火', '温暖,日暖', 'f'], ['昆', '火', '昆山,同也', 'm'],
171
+ ['伶', '火', '伶俐,聪敏', 'f'],
172
+ // ── 扩充:土 ──
173
+ ['山', '土', '山,稳重', 'm'], ['岸', '土', '岸然,独立', 'm'],
174
+ ['岑', '土', '小山,高而静', 'n'], ['巍', '土', '巍峨,高大', 'm'],
175
+ ['嵩', '土', '嵩山,高峻', 'm'], ['岭', '土', '山岭,绵延', 'n'],
176
+ ['奥', '土', '深奥,蕴藉', 'm'], ['宜', '土', '宜然,合度', 'n'],
177
+ ['容', '土', '包容,容仪', 'n'], ['意', '土', '心意,诚意', 'f'],
178
+ ['依', '土', '依倚,亲近', 'f'], ['悠', '土', '悠然,从容', 'f'],
179
+ ['维', '土', '维系,纲维', 'n'], ['纬', '土', '经纬,有条', 'n'],
180
+ ['永', '土', '永恒,久长', 'n'], ['远', '土', '高远', 'm'],
181
+ ['辰', '土', '星辰、辰时', 'm'], ['壁', '土', '壁立,端正', 'm'],
182
+ ['田', '土', '田野,耕获', 'm'], ['由', '土', '由来,自得', 'n'],
183
+ ['画', '土', '图画,文采', 'f'], ['延', '土', '延展,绵长', 'm'],
184
+ ['建', '土', '建立,树也', 'm'], ['音', '土', '音声,和鸣', 'f'],
185
+ ['韵', '土', '韵致,余响', 'f'], ['玮', '土', '美玉,珍奇', 'm'],
186
+ ['雍', '土', '雍容,和穆', 'm'], ['懿', '土', '懿德,美善', 'f'],
187
+ // ── 扩充:金 ──
188
+ ['金', '金', '金,坚而贵', 'm'], ['秋', '金', '秋收、成熟(秋属金,肃而收)', 'n'],
189
+ ['书', '金', '书卷,文墨', 'n'], ['舒', '金', '舒展,从容', 'n'],
190
+ ['善', '金', '善良,善成', 'n'], ['信', '金', '诚信,符信', 'm'],
191
+ ['修', '金', '修远,修身', 'm'], ['素', '金', '素雅,本色', 'f'],
192
+ ['静', '金', '安静,沉静', 'f'], ['心', '金', '心志,中藏', 'f'],
193
+ ['新', '金', '新意,日新', 'n'], ['正', '金', '正直,端正', 'm'],
194
+ ['世', '金', '世代,绵延', 'm'], ['少', '金', '少年,少壮', 'm'],
195
+ ['西', '金', '西方,金位', 'n'], ['白', '金', '洁白,素净', 'n'],
196
+ ['辛', '金', '天干辛,阴金', 'n'], ['成', '金', '成器,成事', 'm'],
197
+ ['利', '金', '利落,锋利', 'm'], ['剑', '金', '剑,刚锐', 'm'],
198
+ ['刚', '金', '刚强,不屈', 'm'], ['则', '金', '法则,有度', 'm'],
199
+ ['初', '金', '初心,开端', 'n'], ['硕', '金', '硕大,学殖', 'm'],
200
+ ['尚', '金', '崇尚,尚贤', 'n'], ['臣', '金', '臣,佐事', 'm'],
201
+ ['川', '金', '川流,通达', 'n'], ['舟', '金', '舟行,济渡', 'n'],
202
+ ['州', '金', '州,聚落', 'n'], ['祖', '金', '祖德,源远', 'm'],
203
+ ['祥', '金', '吉祥,祥瑞', 'n'], ['禄', '金', '福禄,俸给', 'm'],
204
+ ['禧', '金', '禧庆,福', 'n'], ['珍', '金', '珍宝,珍重', 'f'],
205
+ ['宣', '金', '宣明,布达', 'n'], ['序', '金', '秩序,庠序', 'n'],
206
+ ['谦', '金', '谦逊,有终', 'm'], ['赞', '金', '赞美,佐成', 'm'],
207
+ ['超', '金', '超越,越过', 'm'], ['锴', '金', '精铁,坚刚', 'm'],
208
+ // ── 扩充:水 ──
209
+ ['水', '水', '水,润下', 'n'], ['冰', '水', '冰清,澄澈', 'f'],
210
+ ['洁', '水', '洁净,洁身', 'f'], ['浩', '水', '浩大,广远', 'm'],
211
+ ['瀚', '水', '浩瀚,无涯', 'm'], ['渊', '水', '渊深,有本', 'm'],
212
+ ['澜', '水', '波澜,壮阔', 'n'], ['潮', '水', '潮涌,有信', 'n'],
213
+ ['溪', '水', '溪流,清浅', 'f'], ['湘', '水', '湘水,清深', 'f'],
214
+ ['渝', '水', '渝水,守而不变', 'n'], ['深', '水', '深厚,深藏', 'm'],
215
+ ['湛', '水', '湛然,清深', 'm'], ['汇', '水', '汇聚,会归', 'n'],
216
+ ['洲', '水', '洲渚,水中地', 'n'], ['湾', '水', '水湾,曲处', 'f'],
217
+ ['云', '水', '云行,舒卷', 'n'], ['风', '水', '风雅,流动', 'n'],
218
+ ['北', '水', '北方,水位', 'n'], ['冬', '水', '冬藏,静敛', 'f'],
219
+ ['玄', '水', '玄远,幽深', 'n'], ['子', '水', '子,初生', 'm'],
220
+ ['平', '水', '平和,坦易', 'n'], ['方', '水', '方正,有隅', 'n'],
221
+ ['帆', '水', '风帆,顺行', 'n'], ['航', '水', '航行,济远', 'm'],
222
+ ['敏', '水', '敏思,捷悟', 'f'], ['慧', '水', '慧心,明彻', 'f'],
223
+ ['惠', '水', '惠泽,施与', 'f'], ['霈', '水', '霈雨,丰沛', 'm'],
224
+ ['灏', '水', '灏气,广大', 'm'], ['湄', '水', '水湄,岸边', 'f'],
225
+ ['滨', '水', '水滨,近水', 'n'], ['洛', '水', '洛水,清流', 'n'],
226
+ ['津', '水', '津渡,要处', 'n'], ['泊', '水', '淡泊,自守', 'm'],
227
+ ['沧', '水', '沧海,苍茫', 'm'], ['浦', '水', '浦,水滨', 'n'],
119
228
  ];
120
229
 
121
230
  const EL_INDEX = new Map();
@@ -123,6 +232,24 @@ for (const c of CHAR_LIB) {
123
232
  if (!EL_INDEX.has(c[0])) EL_INDEX.set(c[0], { c: c[0], el: c[1], meaning: c[2], g: c[3], order: EL_INDEX.size });
124
233
  }
125
234
 
235
+ /** 用户可自带某字的五行(字库未收时用,按你信的那派算;传了就算「用户指定」)。 */
236
+ function userElement(input, ch) {
237
+ const map = input && input.charElements;
238
+ if (!map || typeof map !== 'object') return null;
239
+ const v = map[ch];
240
+ return ALL.includes(v) ? v : null;
241
+ }
242
+
243
+ /** 喜用五行里挑几个可替换的常用字(同性别倾向优先),给未收录字一个落点。 */
244
+ function suggestFor(element, genderPref, exclude, count = 3) {
245
+ const pool = CHAR_LIB.filter((c) => c[1] === element && !exclude.has(c[0]));
246
+ pool.sort((a, b) => {
247
+ const fit = (x) => (x[3] === genderPref || x[3] === 'n' ? 1 : 0);
248
+ return fit(b) - fit(a);
249
+ });
250
+ return pool.slice(0, count).map((c) => ({ char: c[0], element: c[1], meaning: c[2] }));
251
+ }
252
+
126
253
  const KIND_LABEL = { m: '男', f: '女', n: '中' };
127
254
 
128
255
  /** 喜用五行(简化判定:旺衰 + 生克泄耗)。 */
@@ -178,23 +305,44 @@ export function assessName(input) {
178
305
  baziNote = { dayMaster: r.dayMaster, solarNote: r.solarTime ? r.solarTime.note : '' };
179
306
  }
180
307
 
308
+ const genderPref = input.gender === 'female' ? 'f' : 'm';
309
+ const taken = new Set([surname, ...given]);
310
+ const favPool = favorable.list.length ? favorable.list : ALL.slice();
181
311
  const chars = [...given].map((ch) => {
182
312
  const info = charInfo(ch);
183
- const inFav = info ? favorable.list.includes(info.el) : null;
313
+ const given = userElement(input, ch);
314
+ if (info) {
315
+ return {
316
+ char: ch, element: info.el, meaning: info.meaning,
317
+ genderHint: KIND_LABEL[info.g], favorable: hasBirth ? favorable.list.includes(info.el) : null,
318
+ source: 'lib', note: null,
319
+ };
320
+ }
321
+ if (given) {
322
+ return {
323
+ char: ch, element: given, meaning: '字库未收录;五行按你指定的「' + given + '」计',
324
+ genderHint: null, favorable: hasBirth ? favorable.list.includes(given) : null,
325
+ source: 'user', note: '此字五行由调用方指定,不是字库推断',
326
+ };
327
+ }
184
328
  return {
185
- char: ch,
186
- element: info ? info.el : '未收录',
187
- meaning: info ? info.meaning : '字库未收录,未推断五行',
188
- genderHint: info ? KIND_LABEL[info.g] : null,
189
- favorable: inFav,
329
+ char: ch, element: '未收录', meaning: '字库未收录,未推断五行(不猜)',
330
+ genderHint: null, favorable: null, source: 'none',
331
+ note: hasBirth ? '若想贴合命局,可换用下面的同喜用字' : '字库未收录:给出生辰后可以看同喜用的替换字',
332
+ suggest: hasBirth
333
+ ? favPool.flatMap((el) => suggestFor(el, genderPref, taken, 2))
334
+ : [],
190
335
  };
191
336
  });
192
- const known = chars.filter((c) => c.element !== '未收录').length;
337
+ const known = chars.filter((c) => c.source === 'lib').length;
338
+ const unknown = chars.filter((c) => c.source === 'none').length;
193
339
  const favCount = chars.filter((c) => c.favorable === true).length;
340
+ const judged = chars.length - unknown;
194
341
  let verdict;
195
342
  if (!hasBirth) verdict = '只做了字义与五行归类;给出生年月日才能判断用字是否合喜用。';
196
- else if (favCount === chars.length && chars.length > 0) verdict = `用字都落在喜用(${favorable.list.join('、')})上,与命局方向一致。`;
197
- else if (favCount > 0) verdict = `部分用字合喜用(${favCount}/${chars.length}),其余可再斟酌;喜用为 ${favorable.list.join('、')}。`;
343
+ else if (unknown === chars.length) verdict = `两字都不在字库里,没法判断合不合喜用(喜用为 ${favorable.list.join('、')})。下面给了可替换的常用字,或把你自己认定的五行传进来。`;
344
+ else if (favCount === judged && judged > 0) verdict = `用字都落在喜用(${favorable.list.join('、')})上,与命局方向一致。`;
345
+ else if (favCount > 0) verdict = `部分用字合喜用(${favCount}/${judged}),其余可再斟酌;喜用为 ${favorable.list.join('、')}。`;
198
346
  else verdict = `用字未落在喜用(${favorable.list.join('、')})上;不必然是坏名,但若想贴合命局可换字再看。`;
199
347
 
200
348
  return {
@@ -212,10 +360,10 @@ export function assessName(input) {
212
360
  },
213
361
  } : {}),
214
362
  chars,
215
- stats: { chars: chars.length, known, favorableCount: favCount },
363
+ stats: { chars: chars.length, known, unknown, favorableCount: favCount, libSize: CHAR_LIB.length },
216
364
  verdict,
217
365
  notes: [
218
- '字之五行按通行字义/偏旁归类,自建字库有限:未收录的字不猜五行,如实标注。',
366
+ `字之五行按通行字义/偏旁归类,自建字库共 ${CHAR_LIB.length} 字(常用名用字为主);未收录的字不猜五行,如实标注,「用户指定」是你传入的归类。`,
219
367
  '不做五格剖象(需康熙字典笔画),也不做音韵格律判断——谐音、拗口请自己读三遍或用方言读一遍。',
220
368
  '起名只做用字参考,不替父母做决定。',
221
369
  ],
@@ -267,19 +415,41 @@ export function generateNames(input) {
267
415
  elements: [a[1], b[1]],
268
416
  allFavorable: fav.list.includes(a[1]) && fav.list.includes(b[1]),
269
417
  genderScore: gScore,
270
- order: i * 1000 + j,
418
+ order: (i * 7 + j * 13) % 9973, // 打散字库顺序,避免候选清一色都是前几个字
271
419
  });
272
420
  }
273
421
  }
274
- scored.sort((x, y) => (y.allFavorable - x.allFavorable) || (y.genderScore - x.genderScore) || (x.order - y.order));
422
+ const mixed = (c) => (c.elements[0] !== c.elements[1] ? 1 : 0); // 两字异行,比同气堆叠更有层次
423
+ scored.sort((x, y) => (y.allFavorable - x.allFavorable) || (mixed(y) - mixed(x)) || (y.genderScore - x.genderScore) || (x.order - y.order));
424
+ // 去重 + 用字轮换:先收「两个字都没出现过」的候选,再放宽——避免 20 个候选里 13 个都用同一个「梓」
275
425
  const out = [];
276
- const used = new Set();
277
- for (const cand of scored) {
278
- if (out.length >= limit) break;
426
+ const usedNames = new Set();
427
+ const usedChars = new Set([surname]);
428
+ const usedPairs = new Set();
429
+ const take = (cand, strict, freshPair) => {
279
430
  const key = [...cand.name].sort().join('');
280
- if (used.has(key)) continue;
281
- used.add(key);
431
+ if (usedNames.has(key)) return false;
432
+ if (strict && cand.chars.some((x) => usedChars.has(x.char))) return false;
433
+ const pair = cand.elements.join('');
434
+ if (freshPair && usedPairs.has(pair)) return false;
435
+ usedNames.add(key);
436
+ usedPairs.add(pair);
437
+ cand.chars.forEach((x) => usedChars.add(x.char));
282
438
  out.push({ rank: out.length + 1, name: surname + cand.name, given: cand.name, chars: cand.chars });
439
+ return true;
440
+ };
441
+ // 三轮:①新字 + 新五行组合 ②新字 ③放开——先保证候选之间不撞字、不撞组合
442
+ for (const cand of scored) {
443
+ if (out.length >= limit) break;
444
+ take(cand, true, true);
445
+ }
446
+ for (const cand of scored) {
447
+ if (out.length >= limit) break;
448
+ take(cand, true, false);
449
+ }
450
+ for (const cand of scored) {
451
+ if (out.length >= limit) break;
452
+ take(cand, false, false);
283
453
  }
284
454
  return {
285
455
  system: 'name',
@@ -289,7 +459,7 @@ export function generateNames(input) {
289
459
  bazi: { dayMaster: r.dayMaster, strength, favorable: fav.list, basis: fav.basis },
290
460
  candidates: out,
291
461
  notes: [
292
- `字库共 ${CHAR_LIB.length} 字,只在喜用五行(${fav.list.join('、')})里选字;未覆盖的生僻好字可手工评估。`,
462
+ `字库共 ${CHAR_LIB.length} 字,只在喜用五行(${fav.list.join('、')})里选字;未覆盖的生僻好字可用 charElements 指定五行后评估。`,
293
463
  '候选按合喜用与性别倾向确定性排序,不是「吉名」判定;音韵与方言谐音请自行读念检查。',
294
464
  '不做五格剖象(需康熙字典笔画)。',
295
465
  ],
package/index.js CHANGED
@@ -108,7 +108,7 @@ export function apply(ctx) {
108
108
  system: {
109
109
  type: 'string',
110
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 = 起名(用字五行评估与候选生成);convert = 公农历互转(solar2lunar 公历转农历 / lunar2solar 农历转公历)。',
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 农历转公历)。',
112
112
  },
113
113
  datetime: {
114
114
  type: 'string',
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "dsh-metaphysics",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
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.",
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.",
6
6
  "keywords": [
7
7
  "玄学",
8
8
  "玄学排盘",