mingpan 0.1.3 → 0.1.4

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.
Files changed (134) hide show
  1. package/README.md +56 -11
  2. package/dist/core/bazi/BaziCore.d.ts +7 -1
  3. package/dist/core/bazi/BaziCore.d.ts.map +1 -1
  4. package/dist/core/bazi/BaziCore.js +37 -11
  5. package/dist/core/bazi/BaziCore.js.map +1 -1
  6. package/dist/core/bazi/types.d.ts +4 -0
  7. package/dist/core/bazi/types.d.ts.map +1 -1
  8. package/dist/index.d.ts +10 -5
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +14 -1578
  11. package/dist/index.js.map +1 -1
  12. package/dist/output/fortuneTextRenderer.d.ts +8 -7
  13. package/dist/output/fortuneTextRenderer.d.ts.map +1 -1
  14. package/dist/output/fortuneTextRenderer.js +83 -21
  15. package/dist/output/fortuneTextRenderer.js.map +1 -1
  16. package/dist/output/qimenTextRenderer.d.ts +2 -6
  17. package/dist/output/qimenTextRenderer.d.ts.map +1 -1
  18. package/dist/output/qimenTextRenderer.js +12 -145
  19. package/dist/output/qimenTextRenderer.js.map +1 -1
  20. package/dist/server.d.ts +11 -0
  21. package/dist/server.d.ts.map +1 -0
  22. package/dist/server.js +33 -0
  23. package/dist/server.js.map +1 -0
  24. package/dist/services/bazi/BaziService.d.ts +1 -17
  25. package/dist/services/bazi/BaziService.d.ts.map +1 -1
  26. package/dist/services/bazi/BaziService.js +9 -194
  27. package/dist/services/bazi/BaziService.js.map +1 -1
  28. package/dist/services/bazi/analyzers/TenGodsAnalyzer.js +12 -12
  29. package/dist/services/bazi/analyzers/TenGodsAnalyzer.js.map +1 -1
  30. package/dist/services/bazi/index.d.ts +0 -2
  31. package/dist/services/bazi/index.d.ts.map +1 -1
  32. package/dist/services/bazi/index.js +1 -5
  33. package/dist/services/bazi/index.js.map +1 -1
  34. package/dist/services/bazi/types.d.ts +4 -112
  35. package/dist/services/bazi/types.d.ts.map +1 -1
  36. package/dist/services/bazi/types.js +3 -102
  37. package/dist/services/bazi/types.js.map +1 -1
  38. package/dist/services/daliuren/DaliurenService.d.ts +11 -1
  39. package/dist/services/daliuren/DaliurenService.d.ts.map +1 -1
  40. package/dist/services/daliuren/DaliurenService.js +30 -0
  41. package/dist/services/daliuren/DaliurenService.js.map +1 -1
  42. package/dist/services/daliuren/calculators/TianDiPanCalculator.d.ts.map +1 -1
  43. package/dist/services/daliuren/calculators/TianDiPanCalculator.js +3 -4
  44. package/dist/services/daliuren/calculators/TianDiPanCalculator.js.map +1 -1
  45. package/dist/services/daliuren/data/constants.d.ts +7 -0
  46. package/dist/services/daliuren/data/constants.d.ts.map +1 -1
  47. package/dist/services/daliuren/data/constants.js +17 -1
  48. package/dist/services/daliuren/data/constants.js.map +1 -1
  49. package/dist/services/daliuren/types.d.ts +13 -0
  50. package/dist/services/daliuren/types.d.ts.map +1 -1
  51. package/dist/services/meihua/calculators/TiyongCalculator.d.ts.map +1 -1
  52. package/dist/services/meihua/calculators/TiyongCalculator.js +6 -5
  53. package/dist/services/meihua/calculators/TiyongCalculator.js.map +1 -1
  54. package/dist/services/qimen/QimenService.d.ts +1 -18
  55. package/dist/services/qimen/QimenService.d.ts.map +1 -1
  56. package/dist/services/qimen/QimenService.js +9 -43
  57. package/dist/services/qimen/QimenService.js.map +1 -1
  58. package/dist/services/qimen/calculators/BaMenCalculator.d.ts +14 -22
  59. package/dist/services/qimen/calculators/BaMenCalculator.d.ts.map +1 -1
  60. package/dist/services/qimen/calculators/BaMenCalculator.js +41 -59
  61. package/dist/services/qimen/calculators/BaMenCalculator.js.map +1 -1
  62. package/dist/services/qimen/calculators/JiuGongCalculator.d.ts +6 -13
  63. package/dist/services/qimen/calculators/JiuGongCalculator.d.ts.map +1 -1
  64. package/dist/services/qimen/calculators/JiuGongCalculator.js +11 -41
  65. package/dist/services/qimen/calculators/JiuGongCalculator.js.map +1 -1
  66. package/dist/services/qimen/calculators/JiuXingCalculator.d.ts +13 -23
  67. package/dist/services/qimen/calculators/JiuXingCalculator.d.ts.map +1 -1
  68. package/dist/services/qimen/calculators/JiuXingCalculator.js +23 -68
  69. package/dist/services/qimen/calculators/JiuXingCalculator.js.map +1 -1
  70. package/dist/services/qimen/calculators/JuShuCalculator.d.ts +8 -5
  71. package/dist/services/qimen/calculators/JuShuCalculator.d.ts.map +1 -1
  72. package/dist/services/qimen/calculators/JuShuCalculator.js +14 -19
  73. package/dist/services/qimen/calculators/JuShuCalculator.js.map +1 -1
  74. package/dist/services/qimen/calculators/SanQiLiuYiCalculator.d.ts +11 -20
  75. package/dist/services/qimen/calculators/SanQiLiuYiCalculator.d.ts.map +1 -1
  76. package/dist/services/qimen/calculators/SanQiLiuYiCalculator.js +29 -42
  77. package/dist/services/qimen/calculators/SanQiLiuYiCalculator.js.map +1 -1
  78. package/dist/services/qimen/calculators/ZhuanPanCalculator.d.ts +34 -41
  79. package/dist/services/qimen/calculators/ZhuanPanCalculator.d.ts.map +1 -1
  80. package/dist/services/qimen/calculators/ZhuanPanCalculator.js +102 -130
  81. package/dist/services/qimen/calculators/ZhuanPanCalculator.js.map +1 -1
  82. package/dist/services/qimen/types.d.ts +3 -77
  83. package/dist/services/qimen/types.d.ts.map +1 -1
  84. package/dist/services/qimen/types.js +3 -2
  85. package/dist/services/qimen/types.js.map +1 -1
  86. package/dist/shared/logger.d.ts +5 -0
  87. package/dist/shared/logger.d.ts.map +1 -1
  88. package/dist/shared/logger.js +11 -4
  89. package/dist/shared/logger.js.map +1 -1
  90. package/dist/tools/baziTools.d.ts +13 -0
  91. package/dist/tools/baziTools.d.ts.map +1 -0
  92. package/dist/tools/baziTools.js +331 -0
  93. package/dist/tools/baziTools.js.map +1 -0
  94. package/dist/tools/divinationTools.d.ts +9 -0
  95. package/dist/tools/divinationTools.d.ts.map +1 -0
  96. package/dist/tools/divinationTools.js +209 -0
  97. package/dist/tools/divinationTools.js.map +1 -0
  98. package/dist/tools/qimenTools.d.ts +10 -0
  99. package/dist/tools/qimenTools.d.ts.map +1 -0
  100. package/dist/tools/qimenTools.js +132 -0
  101. package/dist/tools/qimenTools.js.map +1 -0
  102. package/dist/tools/schemas.d.ts +99 -0
  103. package/dist/tools/schemas.d.ts.map +1 -0
  104. package/dist/tools/schemas.js +162 -0
  105. package/dist/tools/schemas.js.map +1 -0
  106. package/dist/tools/ziweiTools.d.ts +14 -0
  107. package/dist/tools/ziweiTools.d.ts.map +1 -0
  108. package/dist/tools/ziweiTools.js +483 -0
  109. package/dist/tools/ziweiTools.js.map +1 -0
  110. package/dist/utils/timeNormalization.d.ts +42 -17
  111. package/dist/utils/timeNormalization.d.ts.map +1 -1
  112. package/dist/utils/timeNormalization.js +99 -41
  113. package/dist/utils/timeNormalization.js.map +1 -1
  114. package/package.json +15 -9
  115. package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.d.ts +0 -16
  116. package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.d.ts.map +0 -1
  117. package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.js +0 -60
  118. package/dist/services/bazi/analyzers/HiddenStemsAnalyzer.js.map +0 -1
  119. package/dist/services/bazi/analyzers/NaYinAnalyzer.d.ts +0 -33
  120. package/dist/services/bazi/analyzers/NaYinAnalyzer.d.ts.map +0 -1
  121. package/dist/services/bazi/analyzers/NaYinAnalyzer.js +0 -209
  122. package/dist/services/bazi/analyzers/NaYinAnalyzer.js.map +0 -1
  123. package/dist/services/bazi/analyzers/ShenShaAnalyzer.d.ts +0 -236
  124. package/dist/services/bazi/analyzers/ShenShaAnalyzer.d.ts.map +0 -1
  125. package/dist/services/bazi/analyzers/ShenShaAnalyzer.js +0 -2079
  126. package/dist/services/bazi/analyzers/ShenShaAnalyzer.js.map +0 -1
  127. package/dist/services/bazi/analyzers/TraditionalAnalyzer.d.ts +0 -46
  128. package/dist/services/bazi/analyzers/TraditionalAnalyzer.d.ts.map +0 -1
  129. package/dist/services/bazi/analyzers/TraditionalAnalyzer.js +0 -260
  130. package/dist/services/bazi/analyzers/TraditionalAnalyzer.js.map +0 -1
  131. package/dist/services/qimen/calculators/ZeRiCalculator.d.ts +0 -78
  132. package/dist/services/qimen/calculators/ZeRiCalculator.d.ts.map +0 -1
  133. package/dist/services/qimen/calculators/ZeRiCalculator.js +0 -431
  134. package/dist/services/qimen/calculators/ZeRiCalculator.js.map +0 -1
package/dist/index.js CHANGED
@@ -3,1597 +3,33 @@
3
3
  /**
4
4
  * Mingpan MCP Server
5
5
  *
6
- * MCP service for accurate BaZi (八字) and ZiWei (紫微) chart calculations.
7
- * Takes birth date/time and outputs structured fortune-telling information.
6
+ * 中華傳統術數 MCP 服務:八字、紫微斗數、六爻、梅花易數、大六壬、奇門遁甲。
7
+ * AI 應用提供確定性排盤與占卜起卦的計算能力。
8
8
  *
9
- * Version 1.1.0: Added fortune list tools for DaYun, LiuNian, LiuYue, LiuRi
10
- * - 八字流月 uses 干支月 (solar term months)
11
- * - 紫微流月 uses 农历月 (lunar months)
9
+ * 架構:
10
+ * - src/tools/ MCP 工具註冊(按領域拆分,共享 schema tools/schemas.ts)
11
+ * - src/services/ 業務計算服務
12
+ * - src/core/ 純計算核心(曆法、規則)
13
+ * - src/output/ 文本渲染
14
+ *
15
+ * 時間口徑:內部規範表示為北京時間(UTC+8);
16
+ * 入口層統一完成農曆轉換與時區換算(見 utils/timeNormalization.ts)。
12
17
  */
13
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- var desc = Object.getOwnPropertyDescriptor(m, k);
16
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
- desc = { enumerable: true, get: function() { return m[k]; } };
18
- }
19
- Object.defineProperty(o, k2, desc);
20
- }) : (function(o, m, k, k2) {
21
- if (k2 === undefined) k2 = k;
22
- o[k2] = m[k];
23
- }));
24
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
- Object.defineProperty(o, "default", { enumerable: true, value: v });
26
- }) : function(o, v) {
27
- o["default"] = v;
28
- });
29
- var __importStar = (this && this.__importStar) || (function () {
30
- var ownKeys = function(o) {
31
- ownKeys = Object.getOwnPropertyNames || function (o) {
32
- var ar = [];
33
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
- return ar;
35
- };
36
- return ownKeys(o);
37
- };
38
- return function (mod) {
39
- if (mod && mod.__esModule) return mod;
40
- var result = {};
41
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
- __setModuleDefault(result, mod);
43
- return result;
44
- };
45
- })();
46
18
  Object.defineProperty(exports, "__esModule", { value: true });
47
- const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
48
19
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
49
- const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
50
- const zod_1 = require("zod");
51
- const zod_to_json_schema_1 = require("zod-to-json-schema");
52
- const lunar_javascript_1 = require("lunar-javascript");
53
20
  const timeNormalization_1 = require("./utils/timeNormalization");
54
- const BaziService_1 = require("./services/bazi/BaziService");
55
- const ZiweiService_1 = require("./services/ziwei/ZiweiService");
56
- const LiuyaoService_1 = require("./services/liuyao/LiuyaoService");
57
- const liuyaoTextRenderer_1 = require("./output/liuyaoTextRenderer");
58
- const MeihuaService_1 = require("./services/meihua/MeihuaService");
59
- const meihuaTextRenderer_1 = require("./output/meihuaTextRenderer");
60
- const DaliurenService_1 = require("./services/daliuren/DaliurenService");
61
- const daliurenTextRenderer_1 = require("./output/daliurenTextRenderer");
62
- const QimenService_1 = require("./services/qimen/QimenService");
63
- const qimenTextRenderer_1 = require("./output/qimenTextRenderer");
64
- const LiuNianCalculator_1 = require("./services/bazi/calculators/LiuNianCalculator");
65
- const DaYunCalculator_1 = require("./services/bazi/calculators/DaYunCalculator");
66
- const LuckCycleCalculator_1 = require("./services/bazi/calculators/LuckCycleCalculator");
67
- const LiuYueCalculator_1 = require("./services/bazi/calculators/LiuYueCalculator");
68
- const LiuRiCalculator_1 = require("./services/bazi/calculators/LiuRiCalculator");
69
- const YearlyCalculator_1 = require("./services/ziwei/calculators/YearlyCalculator");
70
- const fortuneTextRenderer_1 = require("./output/fortuneTextRenderer");
71
- const listTextRenderer_1 = require("./output/listTextRenderer");
72
21
  const logger_1 = require("./shared/logger");
73
- const MutagenCore_1 = require("./core/ziwei/MutagenCore");
22
+ const server_1 = require("./server");
74
23
  const logger = new logger_1.Logger("mingpan");
75
- // ============================================
76
- // Timezone Configuration
77
- // ============================================
78
24
  // Force deterministic timezone behavior (Beijing Time) across environments.
79
- // This ensures lunar-javascript and Date operations behave consistently
25
+ // This ensures Date-based code paths in services behave consistently
80
26
  // regardless of the host machine's timezone setting.
81
- // TODO: Remove when multi-timezone support is implemented (M4 milestone)
82
27
  process.env.TZ = timeNormalization_1.BEIJING_TZ;
83
- // Helper to avoid TypeScript's excessively deep type instantiation error
84
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
- function schemaToJson(schema) {
86
- return (0, zod_to_json_schema_1.zodToJsonSchema)(schema);
87
- }
88
- // ============================================
89
- // Zod Schemas for Tool Inputs
90
- // ============================================
91
- // isLunar field schema (reusable)
92
- const isLunarField = zod_1.z.boolean().optional().default(false).describe("Whether the input date is in lunar calendar (農曆). If true, will be converted to solar calendar internally.");
93
- // Base birth info schema
94
- const BaseBirthInfoSchema = zod_1.z.object({
95
- year: zod_1.z.number().int().min(1900).max(2100).describe("Birth year (e.g., 1990)"),
96
- month: zod_1.z.number().int().min(1).max(12).describe("Birth month (1-12)"),
97
- day: zod_1.z.number().int().min(1).max(31).describe("Birth day (1-31)"),
98
- hour: zod_1.z.number().int().min(0).max(23).describe("Birth hour in 24-hour format (0-23)"),
99
- minute: zod_1.z.number().int().min(0).max(59).optional().default(0).describe("Birth minute (0-59)"),
100
- gender: zod_1.z.enum(["male", "female"]).describe("Gender for fortune direction calculation"),
101
- longitude: zod_1.z.number().min(-180).max(180).optional().describe("Birth location longitude for true solar time adjustment"),
102
- isLunar: isLunarField,
103
- name: zod_1.z.string().optional().describe("Subject name (optional)"),
104
- });
105
- /**
106
- * Normalize birth info: handle lunar-to-solar conversion
107
- * Call this at the start of each handler to get consistent, normalized values
108
- */
109
- function normalizeBirthInfo(input) {
110
- const normalized = (0, timeNormalization_1.normalizeBirthDateTime)({
111
- year: input.year,
112
- month: input.month,
113
- day: input.day,
114
- hour: input.hour,
115
- minute: input.minute,
116
- isLunar: input.isLunar,
117
- });
118
- return {
119
- ...input,
120
- year: normalized.year,
121
- month: normalized.month,
122
- day: normalized.day,
123
- hour: normalized.hour,
124
- minute: normalized.minute,
125
- isLunar: false, // After normalization, always use solar calendar
126
- _isLunarInput: normalized.isLunarInput,
127
- };
128
- }
129
- const BaziCalculateSchema = zod_1.z.object({
130
- year: zod_1.z.number().int().min(1900).max(2100).describe("Birth year (e.g., 1990)"),
131
- month: zod_1.z.number().int().min(1).max(12).describe("Birth month (1-12)"),
132
- day: zod_1.z.number().int().min(1).max(31).describe("Birth day (1-31)"),
133
- hour: zod_1.z.number().int().min(0).max(23).describe("Birth hour in 24-hour format (0-23)"),
134
- minute: zod_1.z.number().int().min(0).max(59).optional().default(0).describe("Birth minute (0-59)"),
135
- gender: zod_1.z.enum(["male", "female"]).optional().default("male").describe("Gender for DaYun calculation direction"),
136
- longitude: zod_1.z.number().min(-180).max(180).optional().describe("Birth location longitude for true solar time adjustment"),
137
- isLunar: isLunarField,
138
- detail: zod_1.z.enum(["simple", "standard", "detailed"]).optional().default("standard").describe("Output detail level"),
139
- includeAnalysis: zod_1.z.boolean().optional().default(true).describe("Include strength and pattern analysis"),
140
- includeDaYun: zod_1.z.boolean().optional().default(true).describe("Include decade fortune (大運)"),
141
- targetYear: zod_1.z.number().int().optional().describe("Calculate LiuNian (流年) for this specific year"),
142
- });
143
- const ZiweiCalculateSchema = zod_1.z.object({
144
- year: zod_1.z.number().int().min(1900).max(2100).describe("Birth year (e.g., 1990)"),
145
- month: zod_1.z.number().int().min(1).max(12).describe("Birth month (1-12)"),
146
- day: zod_1.z.number().int().min(1).max(31).describe("Birth day (1-31)"),
147
- hour: zod_1.z.number().int().min(0).max(23).describe("Birth hour in 24-hour format (0-23)"),
148
- minute: zod_1.z.number().int().min(0).max(59).optional().default(0).describe("Birth minute (0-59)"),
149
- gender: zod_1.z.enum(["male", "female"]).describe("Gender (required for ZiWei calculation)"),
150
- isLunar: isLunarField,
151
- detail: zod_1.z.enum(["simple", "standard", "detailed"]).optional().default("standard").describe("Output detail level"),
152
- targetYear: zod_1.z.number().int().optional().describe("Calculate yearly fortune for this specific year"),
153
- includeDecades: zod_1.z.boolean().optional().default(true).describe("Include decade fortune (大限)"),
154
- includeMutagen: zod_1.z.boolean().optional().default(true).describe("Include four mutagens (四化)"),
155
- });
156
- const CombinedCalculateSchema = zod_1.z.object({
157
- year: zod_1.z.number().int().min(1900).max(2100).describe("Birth year (e.g., 1990)"),
158
- month: zod_1.z.number().int().min(1).max(12).describe("Birth month (1-12)"),
159
- day: zod_1.z.number().int().min(1).max(31).describe("Birth day (1-31)"),
160
- hour: zod_1.z.number().int().min(0).max(23).describe("Birth hour in 24-hour format (0-23)"),
161
- minute: zod_1.z.number().int().min(0).max(59).optional().default(0).describe("Birth minute (0-59)"),
162
- gender: zod_1.z.enum(["male", "female"]).describe("Gender (required for both calculations)"),
163
- longitude: zod_1.z.number().min(-180).max(180).optional().describe("Birth location longitude for true solar time adjustment"),
164
- isLunar: isLunarField,
165
- detail: zod_1.z.enum(["simple", "standard", "detailed"]).optional().default("standard").describe("Output detail level"),
166
- targetYear: zod_1.z.number().int().optional().describe("Calculate yearly fortune for this specific year"),
167
- systems: zod_1.z.array(zod_1.z.enum(["bazi", "ziwei"])).optional().default(["bazi", "ziwei"]).describe("Which systems to calculate"),
168
- });
169
- // ============================================
170
- // 六爻 Schema
171
- // ============================================
172
- const LiuyaoBasicSchema = zod_1.z.object({
173
- yaoValues: zod_1.z.tuple([
174
- zod_1.z.union([zod_1.z.literal(6), zod_1.z.literal(7), zod_1.z.literal(8), zod_1.z.literal(9)]),
175
- zod_1.z.union([zod_1.z.literal(6), zod_1.z.literal(7), zod_1.z.literal(8), zod_1.z.literal(9)]),
176
- zod_1.z.union([zod_1.z.literal(6), zod_1.z.literal(7), zod_1.z.literal(8), zod_1.z.literal(9)]),
177
- zod_1.z.union([zod_1.z.literal(6), zod_1.z.literal(7), zod_1.z.literal(8), zod_1.z.literal(9)]),
178
- zod_1.z.union([zod_1.z.literal(6), zod_1.z.literal(7), zod_1.z.literal(8), zod_1.z.literal(9)]),
179
- zod_1.z.union([zod_1.z.literal(6), zod_1.z.literal(7), zod_1.z.literal(8), zod_1.z.literal(9)]),
180
- ]).describe("六個爻值(自下而上,初爻到上爻)。6=老陰(動), 7=少陽(靜), 8=少陰(靜), 9=老陽(動)"),
181
- year: zod_1.z.number().int().min(1900).max(2100).describe("起卦年份(公曆)"),
182
- month: zod_1.z.number().int().min(1).max(12).describe("起卦月份(1-12)"),
183
- day: zod_1.z.number().int().min(1).max(31).describe("起卦日期(1-31)"),
184
- hour: zod_1.z.number().int().min(0).max(23).describe("起卦時辰(0-23)"),
185
- isLunar: isLunarField,
186
- });
187
- // ============================================
188
- // 梅花易數 Schema
189
- // ============================================
190
- const MeihuaBasicSchema = zod_1.z.object({
191
- method: zod_1.z.enum(['time', 'number']).describe("起卦方式:time=時間起卦,number=數字起卦"),
192
- // time 模式參數
193
- year: zod_1.z.number().int().min(1900).max(2100).optional().describe("起卦年份(公曆,time 模式必填)"),
194
- month: zod_1.z.number().int().min(1).max(12).optional().describe("起卦月份(1-12,time 模式必填)"),
195
- day: zod_1.z.number().int().min(1).max(31).optional().describe("起卦日期(1-31,time 模式必填)"),
196
- hour: zod_1.z.number().int().min(0).max(23).optional().describe("起卦時辰(0-23,time 模式必填)"),
197
- isLunar: isLunarField,
198
- // number 模式參數
199
- upperNumber: zod_1.z.number().int().min(1).optional().describe("上卦數(number 模式必填)"),
200
- lowerNumber: zod_1.z.number().int().min(1).optional().describe("下卦數(number 模式必填)"),
201
- yaoNumber: zod_1.z.number().int().min(1).optional().describe("動爻數(可選,默認用上下卦數之和)"),
202
- });
203
- // ============================================
204
- // 大六壬 Schema
205
- // ============================================
206
- const DaliurenBasicSchema = zod_1.z.object({
207
- jieqi: zod_1.z.string().describe("節氣(如:立春、雨水、驚蟄等)"),
208
- lunarMonth: zod_1.z.number().int().min(1).max(12).describe("農曆月份(1-12)"),
209
- dayGanZhi: zod_1.z.string().describe("日干支(如:甲子、乙丑等)"),
210
- hourGanZhi: zod_1.z.string().describe("時干支(如:甲子、乙丑等)"),
211
- guirenMethod: zod_1.z.union([zod_1.z.literal(0), zod_1.z.literal(1)]).optional().default(0).describe("貴人起法:0=標準, 1=另一種"),
212
- });
213
- // ============================================
214
- // 奇門遁甲 Schema
215
- // ============================================
216
- const QimenBasicSchema = zod_1.z.object({
217
- year: zod_1.z.number().int().min(1900).max(2100).describe("年份(公曆,1900-2100)"),
218
- month: zod_1.z.number().int().min(1).max(12).describe("月份(1-12)"),
219
- day: zod_1.z.number().int().min(1).max(31).describe("日期(1-31)"),
220
- hour: zod_1.z.number().int().min(0).max(23).describe("時辰(0-23,24小時制)"),
221
- minute: zod_1.z.number().int().min(0).max(59).optional().default(0).describe("分鐘(0-59)"),
222
- isLunar: isLunarField,
223
- panType: zod_1.z.enum(['时盘', '日盘', '月盘', '年盘']).optional().default('时盘').describe("盤類型:时盘(默認)、日盘、月盘、年盘"),
224
- panStyle: zod_1.z.enum(['转盘', '飞盘']).optional().default('转盘').describe("盤式:转盘(默認,遵循《神奇之門》)或飞盘"),
225
- zhiRunMethod: zod_1.z.enum(['chaibu', 'maoshan']).optional().default('chaibu').describe("置閏方法:chaibu=拆補法(默認),maoshan=茅山法"),
226
- });
227
- // 奇门用神分析
228
- const QimenYongShenSchema = zod_1.z.object({
229
- year: zod_1.z.number().int().min(1900).max(2100).describe("年份(公曆,1900-2100)"),
230
- month: zod_1.z.number().int().min(1).max(12).describe("月份(1-12)"),
231
- day: zod_1.z.number().int().min(1).max(31).describe("日期(1-31)"),
232
- hour: zod_1.z.number().int().min(0).max(23).describe("時辰(0-23,24小時制)"),
233
- minute: zod_1.z.number().int().min(0).max(59).optional().default(0).describe("分鐘(0-59)"),
234
- isLunar: isLunarField,
235
- panType: zod_1.z.enum(['时盘', '日盘', '月盘', '年盘']).optional().default('时盘').describe("盤類型:时盘(默認)、日盘、月盘、年盘"),
236
- panStyle: zod_1.z.enum(['转盘', '飞盘']).optional().default('转盘').describe("盤式:转盘(默認)或飞盘"),
237
- zhiRunMethod: zod_1.z.enum(['chaibu', 'maoshan']).optional().default('chaibu').describe("置閏方法"),
238
- shiLei: zod_1.z.enum([
239
- '求财', '婚姻', '疾病', '出行', '诉讼', '考试', '工作',
240
- '失物', '置业', '求官', '孕产', '寻人', '合作', '其他'
241
- ]).describe("事類(用於確定用神)"),
242
- nianGan: zod_1.z.enum(['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']).optional().describe("年干(用於年命分析,可選)"),
243
- includeShenSha: zod_1.z.boolean().optional().default(true).describe("是否包含神煞分析"),
244
- });
245
- // 奇门择日
246
- const QimenZeRiSchema = zod_1.z.object({
247
- startYear: zod_1.z.number().int().min(1900).max(2100).describe("起始年份"),
248
- startMonth: zod_1.z.number().int().min(1).max(12).describe("起始月份"),
249
- startDay: zod_1.z.number().int().min(1).max(31).describe("起始日期"),
250
- endYear: zod_1.z.number().int().min(1900).max(2100).describe("結束年份"),
251
- endMonth: zod_1.z.number().int().min(1).max(12).describe("結束月份"),
252
- endDay: zod_1.z.number().int().min(1).max(31).describe("結束日期"),
253
- shiLei: zod_1.z.enum([
254
- '求财', '婚姻', '疾病', '出行', '诉讼', '考试', '工作',
255
- '失物', '置业', '求官', '孕产', '寻人', '合作', '其他'
256
- ]).describe("事類"),
257
- limit: zod_1.z.number().int().min(1).max(50).optional().default(10).describe("返回數量限制(默認10)"),
258
- minScore: zod_1.z.number().int().min(0).max(100).optional().default(60).describe("最小評分閾值(0-100,默認60)"),
259
- includeDirection: zod_1.z.boolean().optional().default(false).describe("是否輸出方位信息"),
260
- excludeJieQiDay: zod_1.z.boolean().optional().default(false).describe("是否排除節氣交接日"),
261
- excludeSuiPo: zod_1.z.boolean().optional().default(false).describe("是否排除歲破日"),
262
- excludeYuePo: zod_1.z.boolean().optional().default(false).describe("是否排除月破日"),
263
- panType: zod_1.z.enum(['时盘', '日盘', '月盘', '年盘']).optional().default('时盘').describe("盤類型"),
264
- panStyle: zod_1.z.enum(['转盘', '飞盘']).optional().default('转盘').describe("盤式"),
265
- zhiRunMethod: zod_1.z.enum(['chaibu', 'maoshan']).optional().default('chaibu').describe("置閏方法"),
266
- });
267
- // ============================================
268
- // List Tool Schemas
269
- // ============================================
270
- // 八字大运列表
271
- const BaziDaYunListSchema = BaseBirthInfoSchema.extend({
272
- count: zod_1.z.number().int().min(1).max(12).optional().default(10).describe("Number of DaYun periods to display (default 10)"),
273
- });
274
- // 八字流年列表
275
- const BaziLiuNianListSchema = BaseBirthInfoSchema.extend({
276
- startYear: zod_1.z.number().int().min(1900).max(2100).describe("Start year for the range"),
277
- endYear: zod_1.z.number().int().min(1900).max(2100).describe("End year for the range"),
278
- });
279
- // 八字流月列表(干支月/节气月)
280
- const BaziLiuYueListSchema = BaseBirthInfoSchema.extend({
281
- ganzhiYear: zod_1.z.union([
282
- zod_1.z.string().describe("GanZhi year like '乙巳'"),
283
- zod_1.z.number().int().min(1900).max(2100).describe("Gregorian year like 2025")
284
- ]).describe("The year to query (either GanZhi string or Gregorian year)"),
285
- });
286
- // 八字流日列表
287
- const BaziLiuRiListSchema = BaseBirthInfoSchema.extend({
288
- ganzhiYear: zod_1.z.union([
289
- zod_1.z.string().describe("GanZhi year like '乙巳'"),
290
- zod_1.z.number().int().min(1900).max(2100).describe("Gregorian year like 2025")
291
- ]).describe("The year of the month"),
292
- ganzhiMonth: zod_1.z.union([
293
- zod_1.z.string().describe("GanZhi month like '丙寅' (month 1 = 寅月)"),
294
- zod_1.z.number().int().min(1).max(12).describe("Month number (1=寅月, 2=卯月, ..., 12=丑月)")
295
- ]).describe("The month to query (either GanZhi string or month number 1-12)"),
296
- });
297
- // 紫微大限列表
298
- const ZiweiDaXianListSchema = BaseBirthInfoSchema.extend({
299
- count: zod_1.z.number().int().min(1).max(12).optional().default(10).describe("Number of decade periods to display (default 10)"),
300
- });
301
- // 紫微小限列表
302
- const ZiweiXiaoXianListSchema = BaseBirthInfoSchema.extend({
303
- startAge: zod_1.z.number().int().min(1).max(120).describe("Start age (nominal age) for the range"),
304
- endAge: zod_1.z.number().int().min(1).max(120).describe("End age (nominal age) for the range"),
305
- });
306
- // 紫微流年列表
307
- const ZiweiLiuNianListSchema = BaseBirthInfoSchema.extend({
308
- startYear: zod_1.z.number().int().min(1900).max(2100).describe("Start year for the range"),
309
- endYear: zod_1.z.number().int().min(1900).max(2100).describe("End year for the range"),
310
- });
311
- // 紫微流月列表(农历月)
312
- const ZiweiLiuYueListSchema = BaseBirthInfoSchema.extend({
313
- lunarYear: zod_1.z.number().int().min(1900).max(2100).describe("The lunar year (Gregorian year) to query"),
314
- });
315
- // 紫微流日列表(农历日)
316
- const ZiweiLiuRiListSchema = BaseBirthInfoSchema.extend({
317
- lunarYear: zod_1.z.number().int().min(1900).max(2100).describe("The lunar year (Gregorian year)"),
318
- lunarMonth: zod_1.z.number().int().min(-12).max(12).describe("Lunar month (1-12, use negative for leap month, e.g. -6 for leap 6th month)"),
319
- });
320
- // ============================================
321
- // Create Server
322
- // ============================================
323
- const server = new index_js_1.Server({
324
- name: "mingpan",
325
- version: "0.1.3",
326
- }, {
327
- capabilities: {
328
- tools: {},
329
- },
330
- });
331
- // ============================================
332
- // Tool Definitions
333
- // ============================================
334
- server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
335
- return {
336
- tools: [
337
- {
338
- name: "bazi_basic",
339
- description: `计算八字命盘(基础排盘)。
340
-
341
- 输入出生时间,返回完整的八字命盘信息:
342
- - 四柱(年柱、月柱、日柱、时柱)干支
343
- - 各柱藏干
344
- - 十神配置
345
- - 五行力量分析(360分制)
346
- - 日主强弱判定
347
- - 格局识别
348
- - 神煞标注
349
-
350
- 输出为结构化文本,便于 AI 分析解读。`,
351
- inputSchema: schemaToJson(BaziCalculateSchema),
352
- },
353
- {
354
- name: "ziwei_basic",
355
- description: `计算紫微斗数命盘(基础排盘)。
356
-
357
- 输入出生时间,返回完整的紫微命盘信息:
358
- - 十二宫位排布及干支
359
- - 各宫主星及亮度(庙/旺/得/利/平/不/陷)
360
- - 各宫辅星配置
361
- - 命宫与身宫位置
362
- - 本命四化(化禄/权/科/忌)
363
-
364
- 输出为结构化文本,便于 AI 分析解读。`,
365
- inputSchema: schemaToJson(ZiweiCalculateSchema),
366
- },
367
- {
368
- name: "bazi_dayun",
369
- description: `八字大运列表。
370
-
371
- 返回命主一生的大运周期(十年一运):
372
- - 大运干支
373
- - 起止虚岁
374
- - 对应公历年份
375
- - 起运方向(顺行/逆行)
376
- - 起运年龄
377
-
378
- 用于了解人生各阶段的运势大框架。`,
379
- inputSchema: schemaToJson(BaziDaYunListSchema),
380
- },
381
- {
382
- name: "bazi_liunian",
383
- description: `八字流年列表。
384
-
385
- 返回指定年份范围内的流年信息:
386
- - 公历年份
387
- - 干支年
388
- - 虚岁
389
- - 所属大运
390
-
391
- 用于分析多年运势趋势。`,
392
- inputSchema: schemaToJson(BaziLiuNianListSchema),
393
- },
394
- {
395
- name: "bazi_liuyue",
396
- description: `八字流月列表。
397
-
398
- 重要:八字流月使用【节气月】,非农历月!
399
- - 以节气为边界(立春起算)
400
- - 寅月(正月)从立春开始,约2月4日
401
- - 丑月(腊月)跨越公历年界
402
-
403
- 返回指定年份的12个月运势:
404
- - 干支月
405
- - 节气起止
406
- - 公历日期范围
407
-
408
- 用于规划年度活动时机。`,
409
- inputSchema: schemaToJson(BaziLiuYueListSchema),
410
- },
411
- {
412
- name: "bazi_liuri",
413
- description: `八字流日列表。
414
-
415
- 返回指定月份内的每日运势(含上下文):
416
- - 当前大运、流年、流月资讯
417
- - 公历日期
418
- - 干支日
419
-
420
- 用于精细的日期选择。`,
421
- inputSchema: schemaToJson(BaziLiuRiListSchema),
422
- },
423
- {
424
- name: "ziwei_daxian",
425
- description: `紫微大限列表。
426
-
427
- 返回命主一生的大限周期(十年一限):
428
- - 起止虚岁
429
- - 对应公历年份
430
- - 大限宫位名称
431
- - 宫内主星配置
432
- - 大限四化
433
-
434
- 用于了解人生各阶段的运势大框架。`,
435
- inputSchema: schemaToJson(ZiweiDaXianListSchema),
436
- },
437
- {
438
- name: "ziwei_xiaoxian",
439
- description: `紫微小限列表。
440
-
441
- 小限是紫微斗数中的年度运限单位,每年一宫:
442
- - 虚岁(1岁起)
443
- - 对应公历年份
444
- - 小限宫位(根据出生年支起宫,男顺女逆)
445
- - 宫内主星
446
- - 所属大限
447
- - 小限四化
448
-
449
- 小限与流年并列但计算方式不同:
450
- - 小限:以出生年支定起宫,逐年移宫
451
- - 流年:以该年地支定宫位
452
-
453
- 层级顺序:大限 > 小限 > 流年 > 流月 > 流日`,
454
- inputSchema: schemaToJson(ZiweiXiaoXianListSchema),
455
- },
456
- {
457
- name: "ziwei_liunian",
458
- description: `紫微流年列表。
459
-
460
- 返回指定年份范围内的流年信息:
461
- - 公历年份
462
- - 干支年
463
- - 虚岁
464
- - 流年宫位
465
- - 宫内主星
466
- - 所属大限
467
- - 流年四化
468
-
469
- 用于分析多年运势趋势。`,
470
- inputSchema: schemaToJson(ZiweiLiuNianListSchema),
471
- },
472
- {
473
- name: "ziwei_liuyue",
474
- description: `紫微流月列表。
475
-
476
- 重要:紫微流月使用【农历月】,非节气月!
477
- - 以农历初一为边界
478
- - 正月从春节开始
479
- - 闰月单独显示(如"闰六月")
480
-
481
- 返回指定年份的流月运势(含上下文):
482
- - 当前大限、小限、流年资讯
483
- - 农历月份及公历日期范围
484
- - 流月宫位及宫内主星
485
- - 完整四化系统(本命/大限/小限/流年/流月)
486
-
487
- 用于规划年度活动时机。`,
488
- inputSchema: schemaToJson(ZiweiLiuYueListSchema),
489
- },
490
- {
491
- name: "ziwei_liuri",
492
- description: `紫微流日列表。
493
-
494
- 返回指定农历月内的每日运势(含上下文):
495
- - 当前大限、小限、流年、流月资讯
496
- - 农历日期与公历日期对照
497
- - 干支日及流日宫位
498
- - 完整四化系统(本命/大限/小限/流年/流月/流日)
499
-
500
- 闰月使用负数表示(如 -6 表示闰六月)。
501
-
502
- 用于精细的日期选择。`,
503
- inputSchema: schemaToJson(ZiweiLiuRiListSchema),
504
- },
505
- {
506
- name: "liuyao_basic",
507
- description: `六爻排盤(基礎排盤)。
508
-
509
- 輸入六個爻值和起卦時間,返回完整的六爻盤面:
510
- - 本卦/變卦(含卦名、卦宮、五行)
511
- - 六爻納甲(每爻地支及五行)
512
- - 六親(父母/兄弟/子孫/妻財/官鬼)
513
- - 六神(青龍/朱雀/勾陳/螣蛇/白虎/玄武)
514
- - 世應位置
515
- - 動爻標註
516
- - 日干支、月建、旬空
517
-
518
- 爻值說明:
519
- - 6 = 老陰(動爻,陰變陽)
520
- - 7 = 少陽(靜爻,陽)
521
- - 8 = 少陰(靜爻,陰)
522
- - 9 = 老陽(動爻,陽變陰)
523
-
524
- 輸入順序:自下而上(初爻到上爻)
525
-
526
- 輸出為 Markdown 格式,便於 AI 分析解讀。`,
527
- inputSchema: schemaToJson(LiuyaoBasicSchema),
528
- },
529
- {
530
- name: "meihua_basic",
531
- description: `梅花易數排盤(基礎排盤)。
532
-
533
- 支持兩種起卦方式:
534
- 1. 時間起卦(method='time'):根據農曆年月日時起卦
535
- 2. 數字起卦(method='number'):根據兩個數字起卦
536
-
537
- 返回完整的梅花盤面:
538
- - 本卦/變卦/互卦
539
- - 上卦/下卦(含卦象、五行)
540
- - 動爻位置
541
- - 體用分析(體卦、用卦、五行生剋關係)
542
- - 起卦數據詳情
543
-
544
- 時間起卦算法(農曆):
545
- - 上卦 = (年干支序數 + 月 + 日) % 8
546
- - 下卦 = (年干支序數 + 月 + 日 + 時辰序數) % 8
547
- - 動爻 = (年干支序數 + 月 + 日 + 時辰序數) % 6
548
-
549
- 輸出為 Markdown 格式,便於 AI 分析解讀。`,
550
- inputSchema: schemaToJson(MeihuaBasicSchema),
551
- },
552
- {
553
- name: "daliuren_basic",
554
- description: `大六壬排盤(基礎排盤)。
555
-
556
- 大六壬是中國古老三大占卜術之一,與奇門遁甲、太乙神數並稱三式。
557
-
558
- 輸入節氣、農曆月、日干支、時干支,返回完整的六壬盤面:
559
- - 天地盤(月將加時辰起盤)
560
- - 四課(日干支推演)
561
- - 三傳(九宗門推演:賊尅、比用、涉害、遙尅、昴星、別責、八專、伏吟、返吟)
562
- - 十二天將(貴人、螣蛇、朱雀、六合、勾陳、青龍、天空、白虎、太常、玄武、太陰、天后)
563
- - 格局判斷
564
- - 神煞(日馬、月馬、丁馬、華蓋、閃電)
565
-
566
- 注意:
567
- - 需要提供節氣(如:立春、雨水、驚蟄等)
568
- - 日干支和時干支需要是完整的干支(如:甲子、乙丑)
569
- - 本工具只負責排盤,斷課解讀交給 Agent
570
-
571
- 輸出為 Markdown 格式,便於 AI 分析解讀。`,
572
- inputSchema: schemaToJson(DaliurenBasicSchema),
573
- },
574
- {
575
- name: "qimen_basic",
576
- description: `奇門遁甲排盤(基礎排盤)。
577
-
578
- 奇門遁甲是中國古代三式之一,與大六壬、太乙神數並稱,用於預測和決策。
579
-
580
- 輸入時間信息,返回完整的奇門盤面:
581
- - 陰陽遁和局數(根據節氣判定)
582
- - 九宮布局(地盤干、天盤干)
583
- - 八門飛布(休、生、傷、杜、景、死、驚、開)
584
- - 九星飛布(天蓬、天芮、天沖、天輔、天禽、天心、天柱、天任、天英)
585
- - 八神排布(值符、螣蛇、太陰、六合、白虎、玄武、九地、九天)
586
- - 旬首信息(符頭、值符星、值使門、空亡)
587
- - 日干/時干落宮
588
- - 格局判斷(吉格/凶格約20-30種)
589
-
590
- 支持選項:
591
- - 盤類型:時盤(默認)、日盤、月盤、年盤
592
- - 盤式:轉盤(默認,遵循《神奇之門》)或飛盤
593
- - 置閏法:拆補法(默認)或茅山法
594
-
595
- 盤類型說明:
596
- - 時盤:以時辰為主導,適用於即時預測
597
- - 日盤:以日干支為主導,適用於當日吉凶
598
- - 月盤:以月干支為主導,適用於月度運勢
599
- - 年盤:以年干支為主導,適用於年度規劃
600
-
601
- 盤式說明:
602
- - 轉盤:天盤、八門、九星按物理方向旋轉(《神奇之門》派)
603
- - 飛盤:天盤、八門、九星按洛書軌跡飛布(傳統飛宮法)
604
-
605
- 輸出為 Markdown 格式,含 ASCII 九宮格,便於 AI 分析解讀。`,
606
- inputSchema: schemaToJson(QimenBasicSchema),
607
- },
608
- {
609
- name: "qimen_yongshen",
610
- description: `奇門遁甲用神分析。
611
-
612
- 在基礎排盤基礎上,根據事類選取用神並分析:
613
-
614
- **支持 14 種事類**:
615
- 求財、婚姻、疾病、出行、訴訟、考試、工作、失物、置業、求官、孕產、尋人、合作、其他
616
-
617
- **分析內容**:
618
- - 主用神/輔用神識別及落宮
619
- - 用神旺相休囚死狀態
620
- - 用神空亡、入墓、擊刑檢測
621
- - 與日干生克關係
622
- - 受格局影響評估
623
- - 主客分析(涉及雙方的事類)
624
- - 年命分析(可選)
625
- - 神煞信息(可選)
626
-
627
- **評分系統**:
628
- 每個用神 0-100 分,綜合考量各因素
629
-
630
- 輸出為結構化 Markdown,便於 AI 斷卦分析。`,
631
- inputSchema: schemaToJson(QimenYongShenSchema),
632
- },
633
- {
634
- name: "qimen_zeri",
635
- description: `奇門遁甲擇日功能。
636
-
637
- 在指定日期範圍內篩選吉時:
638
-
639
- **輸入**:
640
- - 起止日期範圍
641
- - 事類(14 種)
642
- - 可選過濾條件
643
-
644
- **評分維度**:
645
- - 格局評分(吉格加分、凶格減分)
646
- - 用神評分(得位、空墓等)
647
- - 神煞評分(吉神凶煞)
648
-
649
- **過濾條件**:
650
- - 最小評分閾值
651
- - 排除歲破日
652
- - 排除月破日
653
- - 排除節氣交接日
654
-
655
- **輸出**:
656
- - 推薦時辰列表(含評分、評級)
657
- - 有利因素、注意事項
658
- - 可選方位信息(三吉門方位、用神方位)
659
-
660
- **性能目標**:
661
- - 7天:< 2秒
662
- - 30天:< 5秒
663
- - 365天:< 60秒`,
664
- inputSchema: schemaToJson(QimenZeRiSchema),
665
- },
666
- ],
667
- };
668
- });
669
- // ============================================
670
- // Tool Handlers
671
- // ============================================
672
- const baziService = new BaziService_1.BaziService({ debug: false });
673
- const ziweiService = new ZiweiService_1.ZiweiService();
674
- const liuyaoService = new LiuyaoService_1.LiuyaoService();
675
- const meihuaService = new MeihuaService_1.MeihuaService();
676
- // Helper: Calculate year stem and branch
677
- function getYearStemBranch(year) {
678
- const STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
679
- const BRANCHES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];
680
- const baseYear = 1984; // 甲子年
681
- const yearDiff = year - baseYear;
682
- const stemIndex = ((yearDiff % 10) + 10) % 10;
683
- const branchIndex = ((yearDiff % 12) + 12) % 12;
684
- return { stem: STEMS[stemIndex], branch: BRANCHES[branchIndex] };
685
- }
686
- // Helper: Parse GanZhi year input
687
- function parseGanzhiYear(input) {
688
- if (typeof input === 'number') {
689
- const { stem, branch } = getYearStemBranch(input);
690
- return { year: input, ganzhi: stem + branch };
691
- }
692
- // Parse GanZhi string to find year - search nearby years
693
- const currentYear = new Date().getFullYear();
694
- for (let y = currentYear - 60; y <= currentYear + 60; y++) {
695
- const { stem, branch } = getYearStemBranch(y);
696
- if (stem + branch === input) {
697
- return { year: y, ganzhi: input };
698
- }
699
- }
700
- // Default to current year if not found
701
- const { stem, branch } = getYearStemBranch(currentYear);
702
- return { year: currentYear, ganzhi: stem + branch };
703
- }
704
- // Helper: Parse GanZhi month input
705
- function parseGanzhiMonth(input) {
706
- if (typeof input === 'number') {
707
- return input; // 1-12
708
- }
709
- // Parse GanZhi month string to get month index
710
- const BRANCHES = ['寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥', '子', '丑'];
711
- const branch = input.substring(1, 2);
712
- const idx = BRANCHES.indexOf(branch);
713
- return idx >= 0 ? idx + 1 : 1;
714
- }
715
- // Helper: Get month stem branch for a given year and month
716
- function getMonthStemBranch(year, monthNum) {
717
- const STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
718
- const BRANCHES = ['寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥', '子', '丑'];
719
- // Month branch: monthNum 1 = 寅, 2 = 卯, ..., 12 = 丑
720
- const branch = BRANCHES[(monthNum - 1) % 12];
721
- // Month stem depends on year stem
722
- const { stem: yearStem } = getYearStemBranch(year);
723
- const yearStemIndex = STEMS.indexOf(yearStem);
724
- // 五虎遁年起月诀
725
- const firstMonthStemMap = {
726
- 0: 2, // 甲年 -> 丙寅月
727
- 1: 4, // 乙年 -> 戊寅月
728
- 2: 6, // 丙年 -> 庚寅月
729
- 3: 8, // 丁年 -> 壬寅月
730
- 4: 0, // 戊年 -> 甲寅月
731
- 5: 2, // 己年 -> 丙寅月
732
- 6: 4, // 庚年 -> 戊寅月
733
- 7: 6, // 辛年 -> 庚寅月
734
- 8: 8, // 壬年 -> 壬寅月
735
- 9: 0 // 癸年 -> 甲寅月
736
- };
737
- const firstMonthStemIndex = firstMonthStemMap[yearStemIndex];
738
- const monthStemIndex = (firstMonthStemIndex + monthNum - 1) % 10;
739
- return { stem: STEMS[monthStemIndex], branch };
740
- }
741
- server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
742
- const { name, arguments: args } = request.params;
743
- logger.info(`Tool called: ${name}`, args);
744
- try {
745
- // === Existing Chart Calculation Handlers ===
746
- if (name === "bazi_basic") {
747
- const validated = BaziCalculateSchema.parse(args);
748
- const normalized = normalizeBirthInfo(validated);
749
- const result = await baziService.calculate({
750
- year: normalized.year,
751
- month: normalized.month,
752
- day: normalized.day,
753
- hour: normalized.hour,
754
- minute: normalized.minute,
755
- gender: normalized.gender,
756
- longitude: normalized.longitude,
757
- useLunar: false, // Already converted to solar if needed
758
- });
759
- // If targetYear is specified, calculate LiuNian
760
- let liuNianInfo = "";
761
- if (validated.targetYear && result.chart) {
762
- const liuNians = LiuNianCalculator_1.LiuNianCalculator.calculate(result.chart, normalized.year, validated.targetYear, validated.targetYear);
763
- if (liuNians.length > 0) {
764
- const liunian = liuNians[0];
765
- liuNianInfo = `\n\n=== 流年 ${validated.targetYear} ===\n干支:${liunian.stem}${liunian.branch}`;
766
- }
767
- }
768
- const options = {
769
- detail: validated.detail,
770
- includePersonal: false,
771
- includeLocation: !!validated.longitude,
772
- };
773
- const birthDate = new Date(normalized.year, normalized.month - 1, normalized.day, normalized.hour, normalized.minute);
774
- const text = (0, fortuneTextRenderer_1.renderBaziText)({ bazi: result, gender: normalized.gender, birthDate }, options);
775
- return {
776
- content: [
777
- {
778
- type: "text",
779
- text: text + liuNianInfo,
780
- },
781
- ],
782
- };
783
- }
784
- if (name === "ziwei_basic") {
785
- const validated = ZiweiCalculateSchema.parse(args);
786
- const normalized = normalizeBirthInfo(validated);
787
- const result = await ziweiService.calculate({
788
- year: normalized.year,
789
- month: normalized.month,
790
- day: normalized.day,
791
- hour: normalized.hour,
792
- gender: normalized.gender,
793
- });
794
- const options = {
795
- detail: validated.detail,
796
- includePersonal: false,
797
- };
798
- const birthDate = new Date(normalized.year, normalized.month - 1, normalized.day, normalized.hour, normalized.minute);
799
- const text = (0, fortuneTextRenderer_1.renderZiweiText)({
800
- ziwei: result,
801
- gender: normalized.gender,
802
- birthDate,
803
- mutagen: result.mutagenInfo // 傳入四化信息
804
- }, options);
805
- return {
806
- content: [
807
- {
808
- type: "text",
809
- text,
810
- },
811
- ],
812
- };
813
- }
814
- // === 六爻工具處理器 ===
815
- if (name === "liuyao_basic") {
816
- const validated = LiuyaoBasicSchema.parse(args);
817
- const result = liuyaoService.calculate({
818
- yaoValues: validated.yaoValues,
819
- year: validated.year,
820
- month: validated.month,
821
- day: validated.day,
822
- hour: validated.hour,
823
- isLunar: validated.isLunar,
824
- });
825
- const text = (0, liuyaoTextRenderer_1.renderLiuyaoText)(result);
826
- return {
827
- content: [
828
- {
829
- type: "text",
830
- text,
831
- },
832
- ],
833
- };
834
- }
835
- // === 梅花易數工具處理器 ===
836
- if (name === "meihua_basic") {
837
- const validated = MeihuaBasicSchema.parse(args);
838
- const result = meihuaService.calculate({
839
- method: validated.method,
840
- year: validated.year,
841
- month: validated.month,
842
- day: validated.day,
843
- hour: validated.hour,
844
- isLunar: validated.isLunar,
845
- upperNumber: validated.upperNumber,
846
- lowerNumber: validated.lowerNumber,
847
- yaoNumber: validated.yaoNumber,
848
- });
849
- const text = (0, meihuaTextRenderer_1.renderMeihuaText)(result);
850
- return {
851
- content: [
852
- {
853
- type: "text",
854
- text,
855
- },
856
- ],
857
- };
858
- }
859
- // === 大六壬工具處理器 ===
860
- if (name === "daliuren_basic") {
861
- const validated = DaliurenBasicSchema.parse(args);
862
- const daliurenService = new DaliurenService_1.DaliurenService();
863
- const result = daliurenService.calculate({
864
- jieqi: validated.jieqi,
865
- lunarMonth: validated.lunarMonth,
866
- dayGanZhi: validated.dayGanZhi,
867
- hourGanZhi: validated.hourGanZhi,
868
- guirenMethod: validated.guirenMethod,
869
- });
870
- const text = (0, daliurenTextRenderer_1.renderDaliurenText)(result);
871
- return {
872
- content: [
873
- {
874
- type: "text",
875
- text,
876
- },
877
- ],
878
- };
879
- }
880
- // === 奇門遁甲工具處理器 ===
881
- if (name === "qimen_basic") {
882
- const validated = QimenBasicSchema.parse(args);
883
- const normalized = normalizeBirthInfo(validated);
884
- const qimenService = new QimenService_1.QimenService();
885
- const result = qimenService.calculate({
886
- year: normalized.year,
887
- month: normalized.month,
888
- day: normalized.day,
889
- hour: normalized.hour,
890
- minute: normalized.minute,
891
- isLunar: false, // Already converted to solar if needed
892
- panType: validated.panType,
893
- panStyle: validated.panStyle,
894
- zhiRunMethod: validated.zhiRunMethod,
895
- });
896
- const text = (0, qimenTextRenderer_1.renderQimenText)(result);
897
- return {
898
- content: [
899
- {
900
- type: "text",
901
- text,
902
- },
903
- ],
904
- };
905
- }
906
- // === 奇門遁甲用神 ===
907
- if (name === "qimen_yongshen") {
908
- const validated = QimenYongShenSchema.parse(args);
909
- const normalized = normalizeBirthInfo(validated);
910
- const qimenService = new QimenService_1.QimenService();
911
- const result = qimenService.calculateWithYongShen({
912
- year: normalized.year,
913
- month: normalized.month,
914
- day: normalized.day,
915
- hour: normalized.hour,
916
- minute: normalized.minute,
917
- isLunar: false,
918
- panType: validated.panType,
919
- panStyle: validated.panStyle,
920
- zhiRunMethod: validated.zhiRunMethod,
921
- }, validated.shiLei, {
922
- nianGan: validated.nianGan,
923
- includeShenSha: validated.includeShenSha,
924
- });
925
- // 使用渲染器生成输出
926
- const { renderQimenYongShenText } = await Promise.resolve().then(() => __importStar(require("./output/qimenTextRenderer")));
927
- const text = renderQimenYongShenText(result);
928
- return {
929
- content: [
930
- {
931
- type: "text",
932
- text,
933
- },
934
- ],
935
- };
936
- }
937
- if (name === "qimen_zeri") {
938
- const validated = QimenZeRiSchema.parse(args);
939
- const qimenService = new QimenService_1.QimenService();
940
- const results = qimenService.findAuspiciousDates({
941
- startDate: new Date(validated.startYear, validated.startMonth - 1, validated.startDay),
942
- endDate: new Date(validated.endYear, validated.endMonth - 1, validated.endDay),
943
- shiLei: validated.shiLei,
944
- limit: validated.limit,
945
- minScore: validated.minScore,
946
- includeDirection: validated.includeDirection,
947
- excludeJieQiDay: validated.excludeJieQiDay,
948
- excludeSuiPo: validated.excludeSuiPo,
949
- excludeYuePo: validated.excludeYuePo,
950
- panType: validated.panType,
951
- panStyle: validated.panStyle,
952
- zhiRunMethod: validated.zhiRunMethod,
953
- });
954
- // 使用渲染器生成输出
955
- const { renderQimenZeRiText } = await Promise.resolve().then(() => __importStar(require("./output/qimenTextRenderer")));
956
- const text = renderQimenZeRiText(results, validated.shiLei);
957
- return {
958
- content: [
959
- {
960
- type: "text",
961
- text,
962
- },
963
- ],
964
- };
965
- }
966
- // === BaZi List Tool Handlers ===
967
- if (name === "bazi_dayun") {
968
- const validated = BaziDaYunListSchema.parse(args);
969
- const normalized = normalizeBirthInfo(validated);
970
- // Calculate BaZi chart first
971
- const result = await baziService.calculate({
972
- year: normalized.year,
973
- month: normalized.month,
974
- day: normalized.day,
975
- hour: normalized.hour,
976
- minute: normalized.minute,
977
- gender: normalized.gender,
978
- longitude: normalized.longitude,
979
- });
980
- if (!result.chart || !result.birthInfo) {
981
- throw new Error("Failed to calculate BaZi chart");
982
- }
983
- // Calculate DaYun
984
- const daYunList = DaYunCalculator_1.DaYunCalculator.calculate(result.chart, result.birthInfo, normalized.gender, { startYear: normalized.year, endYear: normalized.year + 100 });
985
- // Get direction and start info
986
- const direction = LuckCycleCalculator_1.LuckCycleCalculator.calLuckySequence(normalized.gender, result.chart.year.stem) === 'forward' ? '顺行' : '逆行';
987
- const startAge = daYunList.length > 0 ? daYunList[0].startAge : 1;
988
- const startYear = normalized.year + startAge - 1;
989
- const options = {
990
- name: normalized.name,
991
- birthYear: normalized.year,
992
- birthMonth: normalized.month,
993
- birthDay: normalized.day,
994
- birthHour: normalized.hour,
995
- birthMinute: normalized.minute,
996
- gender: normalized.gender,
997
- dayMaster: result.chart.day.stem,
998
- yearPillar: { stem: result.chart.year.stem, branch: result.chart.year.branch },
999
- monthPillar: { stem: result.chart.month.stem, branch: result.chart.month.branch },
1000
- dayPillar: { stem: result.chart.day.stem, branch: result.chart.day.branch },
1001
- hourPillar: { stem: result.chart.hour.stem, branch: result.chart.hour.branch },
1002
- direction,
1003
- startAge,
1004
- startYear,
1005
- };
1006
- const text = (0, listTextRenderer_1.renderBaziDaYunList)(daYunList.slice(0, validated.count), options);
1007
- return { content: [{ type: "text", text }] };
1008
- }
1009
- if (name === "bazi_liunian") {
1010
- const validated = BaziLiuNianListSchema.parse(args);
1011
- const normalized = normalizeBirthInfo(validated);
1012
- // Calculate BaZi chart first
1013
- const result = await baziService.calculate({
1014
- year: normalized.year,
1015
- month: normalized.month,
1016
- day: normalized.day,
1017
- hour: normalized.hour,
1018
- minute: normalized.minute,
1019
- gender: normalized.gender,
1020
- longitude: normalized.longitude,
1021
- });
1022
- if (!result.chart || !result.birthInfo) {
1023
- throw new Error("Failed to calculate BaZi chart");
1024
- }
1025
- // Calculate DaYun list to match each LiuNian to its DaYun
1026
- const daYunList = DaYunCalculator_1.DaYunCalculator.calculate(result.chart, result.birthInfo, normalized.gender, { startYear: normalized.year, endYear: normalized.year + 100 });
1027
- // Calculate LiuNian for the range
1028
- const liuNianList = LiuNianCalculator_1.LiuNianCalculator.calculate(result.chart, normalized.year, validated.startYear, validated.endYear);
1029
- const options = {
1030
- name: normalized.name,
1031
- birthYear: normalized.year,
1032
- birthMonth: normalized.month,
1033
- birthDay: normalized.day,
1034
- birthHour: normalized.hour,
1035
- birthMinute: normalized.minute,
1036
- gender: normalized.gender,
1037
- dayMaster: result.chart.day.stem,
1038
- yearPillar: { stem: result.chart.year.stem, branch: result.chart.year.branch },
1039
- monthPillar: { stem: result.chart.month.stem, branch: result.chart.month.branch },
1040
- dayPillar: { stem: result.chart.day.stem, branch: result.chart.day.branch },
1041
- hourPillar: { stem: result.chart.hour.stem, branch: result.chart.hour.branch },
1042
- startYear: validated.startYear,
1043
- endYear: validated.endYear,
1044
- daYunList,
1045
- };
1046
- const text = (0, listTextRenderer_1.renderBaziLiuNianList)(liuNianList, options);
1047
- return { content: [{ type: "text", text }] };
1048
- }
1049
- if (name === "bazi_liuyue") {
1050
- const validated = BaziLiuYueListSchema.parse(args);
1051
- const normalized = normalizeBirthInfo(validated);
1052
- const { year: gregorianYear, ganzhi: ganzhiYear } = parseGanzhiYear(validated.ganzhiYear);
1053
- // Calculate BaZi chart first
1054
- const result = await baziService.calculate({
1055
- year: normalized.year,
1056
- month: normalized.month,
1057
- day: normalized.day,
1058
- hour: normalized.hour,
1059
- minute: normalized.minute,
1060
- gender: normalized.gender,
1061
- longitude: normalized.longitude,
1062
- });
1063
- if (!result.chart || !result.birthInfo) {
1064
- throw new Error("Failed to calculate BaZi chart");
1065
- }
1066
- // Get year stem and branch
1067
- const { stem: yearStem, branch: yearBranch } = getYearStemBranch(gregorianYear);
1068
- // Calculate DaYun list to find current DaYun
1069
- const daYunList = DaYunCalculator_1.DaYunCalculator.calculate(result.chart, result.birthInfo, normalized.gender, { startYear: normalized.year, endYear: normalized.year + 100 });
1070
- // Calculate age for the target year (虛歲)
1071
- const targetAge = gregorianYear - normalized.year + 1;
1072
- // Find current DaYun
1073
- let currentDaYun;
1074
- const matchedDaYun = daYunList.find(dy => targetAge >= dy.startAge && targetAge <= dy.endAge);
1075
- if (matchedDaYun) {
1076
- currentDaYun = {
1077
- stem: matchedDaYun.stem,
1078
- branch: matchedDaYun.branch,
1079
- startAge: matchedDaYun.startAge,
1080
- endAge: matchedDaYun.endAge,
1081
- };
1082
- }
1083
- // Calculate current LiuNian
1084
- const liuNianList = LiuNianCalculator_1.LiuNianCalculator.calculate(result.chart, normalized.year, gregorianYear, gregorianYear);
1085
- let currentLiuNian;
1086
- if (liuNianList.length > 0) {
1087
- const ln = liuNianList[0];
1088
- currentLiuNian = {
1089
- stem: ln.stem,
1090
- branch: ln.branch,
1091
- age: ln.age,
1092
- };
1093
- }
1094
- // Calculate LiuYue
1095
- const calculator = new LiuYueCalculator_1.LiuYueCalculator();
1096
- const liuYueList = calculator.calculateLiuYue(yearStem, yearBranch, (result.basic?.dayMasterElement || '木'), (result.traditional?.yongShen?.yongShen || []), {
1097
- year: normalized.year,
1098
- month: normalized.month,
1099
- day: normalized.day,
1100
- hour: normalized.hour,
1101
- minute: normalized.minute,
1102
- }, gregorianYear);
1103
- const options = {
1104
- name: normalized.name,
1105
- birthYear: normalized.year,
1106
- birthMonth: normalized.month,
1107
- birthDay: normalized.day,
1108
- birthHour: normalized.hour,
1109
- birthMinute: normalized.minute,
1110
- gender: normalized.gender,
1111
- dayMaster: result.chart.day.stem,
1112
- yearPillar: { stem: result.chart.year.stem, branch: result.chart.year.branch },
1113
- monthPillar: { stem: result.chart.month.stem, branch: result.chart.month.branch },
1114
- dayPillar: { stem: result.chart.day.stem, branch: result.chart.day.branch },
1115
- hourPillar: { stem: result.chart.hour.stem, branch: result.chart.hour.branch },
1116
- ganzhiYear,
1117
- gregorianYear,
1118
- currentDaYun,
1119
- currentLiuNian,
1120
- };
1121
- const text = (0, listTextRenderer_1.renderBaziLiuYueList)(liuYueList, options);
1122
- return { content: [{ type: "text", text }] };
1123
- }
1124
- if (name === "bazi_liuri") {
1125
- const validated = BaziLiuRiListSchema.parse(args);
1126
- const normalized = normalizeBirthInfo(validated);
1127
- const { year: gregorianYear, ganzhi: ganzhiYear } = parseGanzhiYear(validated.ganzhiYear);
1128
- const monthNum = parseGanzhiMonth(validated.ganzhiMonth);
1129
- // Calculate BaZi chart first
1130
- const result = await baziService.calculate({
1131
- year: normalized.year,
1132
- month: normalized.month,
1133
- day: normalized.day,
1134
- hour: normalized.hour,
1135
- minute: normalized.minute,
1136
- gender: normalized.gender,
1137
- longitude: normalized.longitude,
1138
- });
1139
- if (!result.chart || !result.birthInfo) {
1140
- throw new Error("Failed to calculate BaZi chart");
1141
- }
1142
- // Get year and month stem/branch
1143
- const { stem: yearStem, branch: yearBranch } = getYearStemBranch(gregorianYear);
1144
- const { stem: monthStem, branch: monthBranch } = getMonthStemBranch(gregorianYear, monthNum);
1145
- // Calculate DaYun list to find current DaYun
1146
- const daYunList = DaYunCalculator_1.DaYunCalculator.calculate(result.chart, result.birthInfo, normalized.gender, { startYear: normalized.year, endYear: normalized.year + 100 });
1147
- // Calculate age for the target year (虛歲)
1148
- const targetAge = gregorianYear - normalized.year + 1;
1149
- // Find current DaYun
1150
- let currentDaYun;
1151
- const matchedDaYun = daYunList.find(dy => targetAge >= dy.startAge && targetAge <= dy.endAge);
1152
- if (matchedDaYun) {
1153
- currentDaYun = {
1154
- stem: matchedDaYun.stem,
1155
- branch: matchedDaYun.branch,
1156
- startAge: matchedDaYun.startAge,
1157
- endAge: matchedDaYun.endAge,
1158
- };
1159
- }
1160
- // Calculate current LiuNian
1161
- const liuNianList = LiuNianCalculator_1.LiuNianCalculator.calculate(result.chart, normalized.year, gregorianYear, gregorianYear);
1162
- let currentLiuNian;
1163
- if (liuNianList.length > 0) {
1164
- const ln = liuNianList[0];
1165
- currentLiuNian = {
1166
- stem: ln.stem,
1167
- branch: ln.branch,
1168
- age: ln.age,
1169
- };
1170
- }
1171
- // Current LiuYue info
1172
- const currentLiuYue = {
1173
- stem: monthStem,
1174
- branch: monthBranch,
1175
- month: monthNum,
1176
- };
1177
- // Calculate LiuRi
1178
- const calculator = new LiuRiCalculator_1.LiuRiCalculator();
1179
- const liuRiList = calculator.calculateLiuRi(monthStem, monthBranch, yearStem, yearBranch, (result.basic?.dayMasterElement || '木'), (result.traditional?.yongShen?.yongShen || []), gregorianYear, monthNum);
1180
- // Get the first and last date from the calculated list
1181
- const startDate = liuRiList.length > 0 ? liuRiList[0].date : new Date();
1182
- const endDate = liuRiList.length > 0 ? liuRiList[liuRiList.length - 1].date : new Date();
1183
- const options = {
1184
- name: normalized.name,
1185
- birthYear: normalized.year,
1186
- birthMonth: normalized.month,
1187
- birthDay: normalized.day,
1188
- birthHour: normalized.hour,
1189
- birthMinute: normalized.minute,
1190
- gender: normalized.gender,
1191
- dayMaster: result.chart.day.stem,
1192
- yearPillar: { stem: result.chart.year.stem, branch: result.chart.year.branch },
1193
- monthPillar: { stem: result.chart.month.stem, branch: result.chart.month.branch },
1194
- dayPillar: { stem: result.chart.day.stem, branch: result.chart.day.branch },
1195
- hourPillar: { stem: result.chart.hour.stem, branch: result.chart.hour.branch },
1196
- ganzhiMonth: monthStem + monthBranch,
1197
- ganzhiYear,
1198
- gregorianYear,
1199
- startDate,
1200
- endDate,
1201
- currentDaYun,
1202
- currentLiuNian,
1203
- currentLiuYue,
1204
- };
1205
- const text = (0, listTextRenderer_1.renderBaziLiuRiList)(liuRiList, options);
1206
- return { content: [{ type: "text", text }] };
1207
- }
1208
- // === ZiWei List Tool Handlers ===
1209
- if (name === "ziwei_daxian") {
1210
- const validated = ZiweiDaXianListSchema.parse(args);
1211
- const normalized = normalizeBirthInfo(validated);
1212
- // Calculate ZiWei chart
1213
- const result = ziweiService.calculate({
1214
- year: normalized.year,
1215
- month: normalized.month,
1216
- day: normalized.day,
1217
- hour: normalized.hour,
1218
- gender: normalized.gender,
1219
- });
1220
- if (!result.decades || result.decades.length === 0) {
1221
- throw new Error("Failed to calculate ZiWei decades");
1222
- }
1223
- // Determine direction
1224
- const yangStems = ['甲', '丙', '戊', '庚', '壬'];
1225
- const yearStem = result.basicInfo?.fourPillars?.year?.stem || '';
1226
- const isYang = yangStems.includes(yearStem);
1227
- const isMale = validated.gender === 'male';
1228
- const direction = ((isYang && isMale) || (!isYang && !isMale)) ? '顺行' : '逆行';
1229
- // Find Ming Gong stars
1230
- const mingGongPalace = result.palaces?.find(p => p.name === '命宮' || p.name === '命宫' || p.name === 'Life');
1231
- const mingGongStars = mingGongPalace?.majorStars?.map(s => typeof s === 'string' ? s : s.name) || [];
1232
- // Find Shen Gong
1233
- const shenGongPalace = result.palaces?.find(p => p.isBodyPalace);
1234
- const shenGongStars = shenGongPalace?.majorStars?.map(s => typeof s === 'string' ? s : s.name) || [];
1235
- const options = {
1236
- name: normalized.name,
1237
- birthYear: normalized.year,
1238
- birthMonth: normalized.month,
1239
- birthDay: normalized.day,
1240
- birthHour: normalized.hour,
1241
- birthMinute: normalized.minute,
1242
- gender: normalized.gender,
1243
- mingGong: mingGongPalace?.name || '命宮',
1244
- mingGongStars,
1245
- shenGong: shenGongPalace?.name,
1246
- shenGongStars,
1247
- palaces: result.palaces, // 传入完整宫位数据
1248
- mutagenInfo: result.mutagenInfo, // 传入四化信息
1249
- direction,
1250
- };
1251
- const text = (0, listTextRenderer_1.renderZiweiDaXianList)(result.decades.slice(0, validated.count), options);
1252
- return { content: [{ type: "text", text }] };
1253
- }
1254
- if (name === "ziwei_xiaoxian") {
1255
- const validated = ZiweiXiaoXianListSchema.parse(args);
1256
- const normalized = normalizeBirthInfo(validated);
1257
- const result = ziweiService.calculate({
1258
- year: normalized.year,
1259
- month: normalized.month,
1260
- day: normalized.day,
1261
- hour: normalized.hour,
1262
- gender: normalized.gender,
1263
- });
1264
- if (!result.palaces) {
1265
- throw new Error("Failed to calculate ZiWei chart");
1266
- }
1267
- const minorLimitList = ziweiService.getMinorLimitRange(normalized.year, validated.startAge, validated.endAge);
1268
- const mingGongPalace = result.palaces?.find(p => p.name === '命宮' || p.name === '命宫' || p.name === 'Life');
1269
- const mingGongStars = mingGongPalace?.majorStars?.map(s => typeof s === 'string' ? s : s.name) || [];
1270
- const currentYear = new Date().getFullYear();
1271
- const currentAge = currentYear - normalized.year + 1;
1272
- let currentDecade;
1273
- if (result.decades && result.decades.length > 0) {
1274
- const matchedDecade = result.decades.find(d => currentAge >= d.startAge && currentAge <= d.endAge);
1275
- if (matchedDecade) {
1276
- currentDecade = {
1277
- palaceName: matchedDecade.palaceName || result.palaces?.[matchedDecade.palaceIndex]?.name || '未知',
1278
- startAge: matchedDecade.startAge,
1279
- endAge: matchedDecade.endAge,
1280
- };
1281
- }
1282
- }
1283
- const options = {
1284
- name: normalized.name,
1285
- birthYear: normalized.year,
1286
- birthMonth: normalized.month,
1287
- birthDay: normalized.day,
1288
- birthHour: normalized.hour,
1289
- birthMinute: normalized.minute,
1290
- gender: normalized.gender,
1291
- mingGong: mingGongPalace?.name || '命宮',
1292
- mingGongStars,
1293
- palaces: result.palaces,
1294
- mutagenInfo: result.mutagenInfo,
1295
- startAge: validated.startAge,
1296
- endAge: validated.endAge,
1297
- currentDecade,
1298
- decades: result.decades,
1299
- };
1300
- const text = (0, listTextRenderer_1.renderZiweiXiaoXianList)(minorLimitList, options);
1301
- return { content: [{ type: "text", text }] };
1302
- }
1303
- if (name === "ziwei_liunian") {
1304
- const validated = ZiweiLiuNianListSchema.parse(args);
1305
- const normalized = normalizeBirthInfo(validated);
1306
- // Calculate ZiWei chart
1307
- const result = ziweiService.calculate({
1308
- year: normalized.year,
1309
- month: normalized.month,
1310
- day: normalized.day,
1311
- hour: normalized.hour,
1312
- gender: normalized.gender,
1313
- });
1314
- if (!result.palaces) {
1315
- throw new Error("Failed to calculate ZiWei chart");
1316
- }
1317
- // Calculate yearly info for each year in the range
1318
- const yearlyList = [];
1319
- for (let year = validated.startYear; year <= validated.endYear; year++) {
1320
- const yearly = YearlyCalculator_1.YearlyCalculator.calculate(year, normalized.year, result.palaces);
1321
- if (yearly) {
1322
- yearlyList.push(yearly);
1323
- }
1324
- }
1325
- // Find Ming Gong
1326
- const mingGongPalace = result.palaces?.find(p => p.name === '命宮' || p.name === '命宫' || p.name === 'Life');
1327
- const mingGongStars = mingGongPalace?.majorStars?.map(s => typeof s === 'string' ? s : s.name) || [];
1328
- const options = {
1329
- name: normalized.name,
1330
- birthYear: normalized.year,
1331
- birthMonth: normalized.month,
1332
- birthDay: normalized.day,
1333
- birthHour: normalized.hour,
1334
- birthMinute: normalized.minute,
1335
- gender: normalized.gender,
1336
- mingGong: mingGongPalace?.name || '命宮',
1337
- mingGongStars,
1338
- palaces: result.palaces, // 传入完整宫位数据
1339
- mutagenInfo: result.mutagenInfo, // 传入四化信息
1340
- startYear: validated.startYear,
1341
- endYear: validated.endYear,
1342
- decades: result.decades, // 传入大限列表用于匹配所属大限
1343
- };
1344
- const text = (0, listTextRenderer_1.renderZiweiLiuNianList)(yearlyList, options);
1345
- return { content: [{ type: "text", text }] };
1346
- }
1347
- if (name === "ziwei_liuyue") {
1348
- const validated = ZiweiLiuYueListSchema.parse(args);
1349
- const normalized = normalizeBirthInfo(validated);
1350
- // Calculate ZiWei chart
1351
- const result = ziweiService.calculate({
1352
- year: normalized.year,
1353
- month: normalized.month,
1354
- day: normalized.day,
1355
- hour: normalized.hour,
1356
- gender: normalized.gender,
1357
- });
1358
- // Get yearly months (农历月)
1359
- const monthlyList = ziweiService.getYearlyMonths(validated.lunarYear);
1360
- // Find Ming Gong
1361
- const mingGongPalace = result.palaces?.find(p => p.name === '命宮' || p.name === '命宫' || p.name === 'Life');
1362
- const mingGongStars = mingGongPalace?.majorStars?.map(s => typeof s === 'string' ? s : s.name) || [];
1363
- // Check for leap month in this lunar year
1364
- const lunar = lunar_javascript_1.Lunar.fromYmd(validated.lunarYear, 1, 1);
1365
- const leapMonth = lunar.getYear() === validated.lunarYear ?
1366
- lunar_javascript_1.Lunar.fromYmd(validated.lunarYear, 6, 1).getLeapMonth?.() : undefined;
1367
- // Calculate age for the target year (虛歲)
1368
- const targetAge = validated.lunarYear - normalized.year + 1;
1369
- // Find current decade (大限)
1370
- let currentDecade;
1371
- if (result.decades && result.decades.length > 0) {
1372
- const matchedDecade = result.decades.find(d => targetAge >= d.startAge && targetAge <= d.endAge);
1373
- if (matchedDecade) {
1374
- currentDecade = {
1375
- palaceName: matchedDecade.palaceName || result.palaces?.[matchedDecade.palaceIndex]?.name || '未知',
1376
- startAge: matchedDecade.startAge,
1377
- endAge: matchedDecade.endAge,
1378
- };
1379
- }
1380
- }
1381
- // Calculate current yearly (流年)
1382
- const yearlyInfo = YearlyCalculator_1.YearlyCalculator.calculate(validated.lunarYear, normalized.year, result.palaces);
1383
- let currentYearly;
1384
- if (yearlyInfo) {
1385
- const { stem: yearStem, branch: yearBranch } = getYearStemBranch(validated.lunarYear);
1386
- currentYearly = {
1387
- year: validated.lunarYear,
1388
- age: targetAge,
1389
- palaceName: result.palaces?.[yearlyInfo.palaceIndex]?.name || '未知',
1390
- heavenlyStem: yearStem,
1391
- earthlyBranch: yearBranch,
1392
- };
1393
- }
1394
- // Calculate current minor limit (小限)
1395
- const minorLimitInfo = ziweiService.getMinorLimitInfo(normalized.year, validated.lunarYear);
1396
- let currentMinorLimit;
1397
- if (minorLimitInfo) {
1398
- currentMinorLimit = {
1399
- age: minorLimitInfo.age,
1400
- palaceName: result.palaces?.[minorLimitInfo.palaceIndex]?.name || '未知',
1401
- heavenlyStem: minorLimitInfo.heavenlyStem,
1402
- earthlyBranch: minorLimitInfo.earthlyBranch,
1403
- };
1404
- }
1405
- // 添加小限四化到 mutagenInfo
1406
- const enhancedMutagenInfo = { ...result.mutagenInfo };
1407
- if (minorLimitInfo?.heavenlyStem) {
1408
- enhancedMutagenInfo.minorLimit = MutagenCore_1.MutagenCore.getMutagen(minorLimitInfo.heavenlyStem) || undefined;
1409
- }
1410
- const options = {
1411
- name: normalized.name,
1412
- birthYear: normalized.year,
1413
- birthMonth: normalized.month,
1414
- birthDay: normalized.day,
1415
- birthHour: normalized.hour,
1416
- birthMinute: normalized.minute,
1417
- gender: normalized.gender,
1418
- mingGong: mingGongPalace?.name || '命宮',
1419
- mingGongStars,
1420
- palaces: result.palaces,
1421
- mutagenInfo: enhancedMutagenInfo,
1422
- lunarYear: validated.lunarYear,
1423
- gregorianYear: validated.lunarYear,
1424
- leapMonth: typeof leapMonth === 'number' ? leapMonth : undefined,
1425
- currentDecade,
1426
- currentMinorLimit,
1427
- currentYearly,
1428
- };
1429
- const text = (0, listTextRenderer_1.renderZiweiLiuYueList)(monthlyList, options);
1430
- return { content: [{ type: "text", text }] };
1431
- }
1432
- if (name === "ziwei_liuri") {
1433
- const validated = ZiweiLiuRiListSchema.parse(args);
1434
- const normalized = normalizeBirthInfo(validated);
1435
- // Calculate ZiWei chart
1436
- const result = ziweiService.calculate({
1437
- year: normalized.year,
1438
- month: normalized.month,
1439
- day: normalized.day,
1440
- hour: normalized.hour,
1441
- gender: normalized.gender,
1442
- });
1443
- // Handle leap month (negative number)
1444
- const isLeapMonth = validated.lunarMonth < 0;
1445
- const actualMonth = Math.abs(validated.lunarMonth);
1446
- // Get lunar month boundaries
1447
- const monthParam = isLeapMonth ? -actualMonth : actualMonth;
1448
- const lunarFirstDay = lunar_javascript_1.Lunar.fromYmd(validated.lunarYear, monthParam, 1);
1449
- // Find last day of the month
1450
- let lastDayNum = 29;
1451
- try {
1452
- lunar_javascript_1.Lunar.fromYmd(validated.lunarYear, monthParam, 30);
1453
- lastDayNum = 30;
1454
- }
1455
- catch {
1456
- // Month only has 29 days
1457
- }
1458
- const lunarLastDay = lunar_javascript_1.Lunar.fromYmd(validated.lunarYear, monthParam, lastDayNum);
1459
- // Convert to solar dates
1460
- const firstSolar = lunarFirstDay.getSolar();
1461
- const lastSolar = lunarLastDay.getSolar();
1462
- const startDate = new Date(firstSolar.getYear(), firstSolar.getMonth() - 1, firstSolar.getDay());
1463
- const endDate = new Date(lastSolar.getYear(), lastSolar.getMonth() - 1, lastSolar.getDay());
1464
- // Build daily list
1465
- const dailyList = [];
1466
- for (let day = 1; day <= lastDayNum; day++) {
1467
- try {
1468
- const lunarDay = lunar_javascript_1.Lunar.fromYmd(validated.lunarYear, monthParam, day);
1469
- const solarDay = lunarDay.getSolar();
1470
- const solarDate = new Date(solarDay.getYear(), solarDay.getMonth() - 1, solarDay.getDay());
1471
- // Get daily info from calculator
1472
- const dailyInfo = ziweiService.getDailyInfo(solarDay.getYear(), solarDay.getMonth(), solarDay.getDay());
1473
- dailyList.push({
1474
- lunarMonth: actualMonth,
1475
- lunarDay: day,
1476
- isLeapMonth,
1477
- gregorianDate: solarDate,
1478
- ganzhi: dailyInfo ? `${dailyInfo.heavenlyStem}${dailyInfo.earthlyBranch}` : '',
1479
- palaceIndex: dailyInfo?.palaceIndex || 0,
1480
- });
1481
- }
1482
- catch (e) {
1483
- // Skip invalid dates
1484
- }
1485
- }
1486
- // Find Ming Gong
1487
- const mingGongPalace = result.palaces?.find(p => p.name === '命宮' || p.name === '命宫' || p.name === 'Life');
1488
- const mingGongStars = mingGongPalace?.majorStars?.map(s => typeof s === 'string' ? s : s.name) || [];
1489
- // Get monthly palace
1490
- const monthlyInfo = ziweiService.getMonthlyInfo(validated.lunarYear, actualMonth - 1, actualMonth, isLeapMonth);
1491
- const monthlyPalace = monthlyInfo ? result.palaces?.[monthlyInfo.palaceIndex]?.name : undefined;
1492
- // Calculate age for the target year (虛歲)
1493
- const targetAge = validated.lunarYear - normalized.year + 1;
1494
- // Find current decade (大限)
1495
- let currentDecade;
1496
- if (result.decades && result.decades.length > 0) {
1497
- const matchedDecade = result.decades.find(d => targetAge >= d.startAge && targetAge <= d.endAge);
1498
- if (matchedDecade) {
1499
- currentDecade = {
1500
- palaceName: matchedDecade.palaceName || result.palaces?.[matchedDecade.palaceIndex]?.name || '未知',
1501
- startAge: matchedDecade.startAge,
1502
- endAge: matchedDecade.endAge,
1503
- };
1504
- }
1505
- }
1506
- // Calculate current yearly (流年)
1507
- const yearlyInfo = YearlyCalculator_1.YearlyCalculator.calculate(validated.lunarYear, normalized.year, result.palaces);
1508
- let currentYearly;
1509
- if (yearlyInfo) {
1510
- const { stem: yearStem, branch: yearBranch } = getYearStemBranch(validated.lunarYear);
1511
- currentYearly = {
1512
- year: validated.lunarYear,
1513
- age: targetAge,
1514
- palaceName: result.palaces?.[yearlyInfo.palaceIndex]?.name || '未知',
1515
- heavenlyStem: yearStem,
1516
- earthlyBranch: yearBranch,
1517
- };
1518
- }
1519
- // Current monthly info (流月)
1520
- let currentMonthly;
1521
- if (monthlyInfo) {
1522
- currentMonthly = {
1523
- month: actualMonth,
1524
- palaceName: result.palaces?.[monthlyInfo.palaceIndex]?.name || '未知',
1525
- heavenlyStem: monthlyInfo.heavenlyStem,
1526
- earthlyBranch: monthlyInfo.earthlyBranch,
1527
- };
1528
- }
1529
- // Calculate current minor limit (小限)
1530
- const minorLimitInfo = ziweiService.getMinorLimitInfo(normalized.year, validated.lunarYear);
1531
- let currentMinorLimit;
1532
- if (minorLimitInfo) {
1533
- currentMinorLimit = {
1534
- age: minorLimitInfo.age,
1535
- palaceName: result.palaces?.[minorLimitInfo.palaceIndex]?.name || '未知',
1536
- heavenlyStem: minorLimitInfo.heavenlyStem,
1537
- earthlyBranch: minorLimitInfo.earthlyBranch,
1538
- };
1539
- }
1540
- // 计算小限四化和流月四化
1541
- const enhancedMutagenInfo = { ...result.mutagenInfo };
1542
- if (minorLimitInfo?.heavenlyStem) {
1543
- enhancedMutagenInfo.minorLimit = MutagenCore_1.MutagenCore.getMutagen(minorLimitInfo.heavenlyStem) || undefined;
1544
- }
1545
- if (monthlyInfo?.heavenlyStem) {
1546
- enhancedMutagenInfo.monthly = MutagenCore_1.MutagenCore.getMutagen(monthlyInfo.heavenlyStem) || undefined;
1547
- }
1548
- const options = {
1549
- name: normalized.name,
1550
- birthYear: normalized.year,
1551
- birthMonth: normalized.month,
1552
- birthDay: normalized.day,
1553
- birthHour: normalized.hour,
1554
- birthMinute: normalized.minute,
1555
- gender: normalized.gender,
1556
- mingGong: mingGongPalace?.name || '命宮',
1557
- mingGongStars,
1558
- palaces: result.palaces,
1559
- mutagenInfo: enhancedMutagenInfo,
1560
- lunarYear: validated.lunarYear,
1561
- lunarMonth: actualMonth,
1562
- isLeapMonth,
1563
- gregorianStartDate: startDate,
1564
- gregorianEndDate: endDate,
1565
- monthlyPalace,
1566
- currentDecade,
1567
- currentMinorLimit,
1568
- currentYearly,
1569
- currentMonthly,
1570
- };
1571
- const text = (0, listTextRenderer_1.renderZiweiLiuRiList)(dailyList, options);
1572
- return { content: [{ type: "text", text }] };
1573
- }
1574
- throw new Error(`Unknown tool: ${name}`);
1575
- }
1576
- catch (error) {
1577
- logger.error(`Tool ${name} failed`, error);
1578
- const errorMessage = error instanceof Error ? error.message : String(error);
1579
- return {
1580
- content: [
1581
- {
1582
- type: "text",
1583
- text: `Error: ${errorMessage}`,
1584
- },
1585
- ],
1586
- isError: true,
1587
- };
1588
- }
1589
- });
1590
- // ============================================
1591
- // Start Server
1592
- // ============================================
1593
28
  async function main() {
29
+ const server = (0, server_1.createMingpanServer)();
1594
30
  const transport = new stdio_js_1.StdioServerTransport();
1595
31
  await server.connect(transport);
1596
- logger.info("Mingpan MCP server started (v0.1.3)");
32
+ logger.info(`Mingpan MCP server started (v${server_1.SERVER_VERSION})`);
1597
33
  }
1598
34
  main().catch((error) => {
1599
35
  logger.error("Server failed to start", error);