guanwei 1.3.1 → 1.3.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.
- package/README.md +28 -8
- package/dist/assets/index-DVd66cjI.js +102 -0
- package/dist/index.html +1 -1
- package/package.json +13 -7
- package/packages/guanwei-api/package.json +26 -0
- package/packages/guanwei-api/src/mcp-http.ts +89 -0
- package/packages/guanwei-api/src/mcp.ts +108 -0
- package/packages/guanwei-api/src/routes/arts.ts +23 -0
- package/packages/guanwei-api/src/routes/chart.ts +24 -0
- package/packages/guanwei-api/src/server.ts +73 -0
- package/scripts/check-boundary.mjs +80 -0
- package/scripts/check-package.mjs +71 -0
- package/scripts/credentials.mjs +52 -0
- package/scripts/github-history-cleanup.mjs +140 -0
- package/scripts/npm-release.mjs +79 -0
- package/scripts/preflight-release.sh +29 -0
- package/scripts/release.sh +8 -3
- package/server/package.json +24 -0
- package/server/src/index.ts +58 -16
- package/server/src/routes/ai.ts +11 -17
- package/server/src/routes/divine.ts +36 -29
- package/server/src/routes/hour.ts +4 -0
- package/server/src/routes/tarot.ts +30 -7
- package/server/src/routes/users.ts +99 -48
- package/server/src/services/auth.ts +53 -0
- package/server/src/services/chartBrief.ts +10 -0
- package/server/src/services/dataDir.ts +80 -0
- package/server/src/services/divineStore.ts +5 -2
- package/server/src/services/duanyu.ts +3 -3
- package/server/src/services/llmProvider.ts +4 -3
- package/server/src/services/usersDb.ts +45 -0
- package/shared/core/data/gua64.ts +5 -5
- package/shared/core/data/qimen.ts +11 -9
- package/shared/core/data/ziwei.ts +20 -15
- package/shared/core/engine/bazi.ts +64 -13
- package/shared/core/engine/calendar.ts +18 -5
- package/shared/core/engine/chart.ts +3 -1
- package/shared/core/engine/liuren.ts +32 -13
- package/shared/core/engine/liuyao.ts +6 -1
- package/shared/core/engine/qimen.ts +102 -60
- package/shared/core/engine/trueSolarTime.ts +9 -6
- package/shared/core/engine/xiaoliuren.ts +6 -2
- package/shared/core/engine/ziwei.ts +55 -1
- package/shared/core/types.ts +10 -6
- package/src/components/arts/XiaoliurenArt.tsx +1 -1
- package/src/pages/DemoPage.tsx +1 -1
- package/src/services/api.ts +18 -1
- package/src/utils/userStore.ts +6 -2
- package/vite.config.ts +7 -3
- package/dist/assets/index-O2O9peYE.js +0 -102
- package/dist/assets/index-O2O9peYE.js.map +0 -1
- package/server/src/data/db.json +0 -7016
- package/server/src/data/guanwei.db +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { NAYIN, ganZhiIndex, mod } from '../data/ganzhi';
|
|
3
3
|
import { GAN } from '../data/ganzhi';
|
|
4
4
|
import { trueSolarTime } from './trueSolarTime';
|
|
5
|
+
import { daysSince } from './calendar';
|
|
5
6
|
import type { ZiweiInput, ZiweiResult } from '../types';
|
|
6
7
|
|
|
7
8
|
import { PALACE_NAMES, ZW_SIHUA, ZW_BRIGHTNESS, LU_CUN, KUI_YUE, TIAN_MA, HUO_START, LING_START, ZW_GEJU } from '../data/ziwei';
|
|
@@ -124,6 +125,21 @@ export function ziweiCalc(input: ZiweiInput): ZiweiResult {
|
|
|
124
125
|
fuStars['天哭'] = mod(yearZhiIdx + 6, 12); // 午起子年顺行
|
|
125
126
|
fuStars['天虚'] = mod(fuStars['天哭'] + 6, 12);
|
|
126
127
|
|
|
128
|
+
/* 1.6 杂曜(修正反馈:辅星/杂曜覆盖有限,2026-09-05 补常用)
|
|
129
|
+
三台/八座:日支起子时顺/逆数至生时(日支由公历日期推,同八字历元) */
|
|
130
|
+
const dayZhiIdx = input.solarDate
|
|
131
|
+
? mod(daysSince(input.solarDate[0], input.solarDate[1], input.solarDate[2]) + 55, 60) % 12
|
|
132
|
+
: 0;
|
|
133
|
+
fuStars['三台'] = mod(dayZhiIdx + correctedHour, 12);
|
|
134
|
+
fuStars['八座'] = mod(dayZhiIdx - correctedHour, 12);
|
|
135
|
+
// 天才/天寿(年干禄存、年支起法)
|
|
136
|
+
const luIdx2 = LU_CUN[gan] ? zhiIdx(LU_CUN[gan]) : 0;
|
|
137
|
+
fuStars['天才'] = mod(luIdx2 + correctedHour, 12);
|
|
138
|
+
fuStars['天寿'] = mod(yearZhiIdx + 5, 12); // 子年起未宫顺行(近似,无古籍精确法时按口诀)
|
|
139
|
+
// 恩光/天贵(年干禄存宫起,恩光顺行、天贵逆行)
|
|
140
|
+
fuStars['恩光'] = mod(luIdx2 + correctedHour, 12);
|
|
141
|
+
fuStars['天贵'] = mod(luIdx2 + 6 - correctedHour, 12);
|
|
142
|
+
|
|
127
143
|
/* 2. 生年四化 */
|
|
128
144
|
const sh = ZW_SIHUA[gan] || { lu: '', quan: '', ke: '', ji: '' };
|
|
129
145
|
const sihua = { lu: sh.lu, quan: sh.quan, ke: sh.ke, ji: sh.ji };
|
|
@@ -140,6 +156,20 @@ export function ziweiCalc(input: ZiweiInput): ZiweiResult {
|
|
|
140
156
|
brightness[s] = (ZW_BRIGHTNESS[s] || [])[pos] || '平';
|
|
141
157
|
});
|
|
142
158
|
|
|
159
|
+
/* 3.1 昼夜调整(修正反馈:太阳喜昼、太阴喜夜,brightness 只按宫位未计生时昼夜)
|
|
160
|
+
规则:昼生(卯~申时支 3..8,时辰序 0=子)太阳+1 级、太阴-1 级;夜生反之;庙/陷为界不越
|
|
161
|
+
(2026-09 修正:原 2..7 实为寅~未,把凌晨寅时误判为昼、下午申时误判为夜;昼夜分界按卯~申对齐) */
|
|
162
|
+
const LV: Record<string, number> = { 不: 1, 陷: 1, 平: 2, 利: 3, 得: 4, 旺: 5, 庙: 6 };
|
|
163
|
+
const LV_NAME = ['', '陷', '平', '利', '得', '旺', '庙'];
|
|
164
|
+
const dayNight: 'day' | 'night' = correctedHour >= 3 && correctedHour <= 8 ? 'day' : 'night';
|
|
165
|
+
const effBrightness: Record<string, string> = {};
|
|
166
|
+
for (const s of Object.keys(brightness)) {
|
|
167
|
+
let lv = LV[brightness[s]] || 2;
|
|
168
|
+
if (s === '太阳') lv += dayNight === 'day' ? 1 : -1;
|
|
169
|
+
if (s === '太阴') lv += dayNight === 'night' ? 1 : -1;
|
|
170
|
+
effBrightness[s] = LV_NAME[Math.max(1, Math.min(6, lv))];
|
|
171
|
+
}
|
|
172
|
+
|
|
143
173
|
/* 4. 格局识别 */
|
|
144
174
|
const geju: ZiweiResult['geju'] = [];
|
|
145
175
|
const pushGeju = (key: string, why: string) => {
|
|
@@ -191,6 +221,30 @@ export function ziweiCalc(input: ZiweiInput): ZiweiResult {
|
|
|
191
221
|
if (zwStars['廉贞'] === zwStars['七杀']) pushGeju('廉贞七杀', '廉贞七杀同守 ' + DIZHI[zwStars['廉贞']] + ' 宫');
|
|
192
222
|
// 命无正曜
|
|
193
223
|
if (mingStars.length === 0) pushGeju('命无正曜', '命宫无十四主星,借对宫 ' + [...new Set(duiStars)].join('、') + ' 为用');
|
|
224
|
+
// 水澄桂萼:太阴在子庙且坐命/命三方(传统格须太阴得地于命局关键位)
|
|
225
|
+
const moonPos = zwStars['太阴'];
|
|
226
|
+
const moonInKey = moonPos !== undefined && (moonPos === ming || sanhe.includes(moonPos));
|
|
227
|
+
if (moonInKey && effBrightness['太阴'] === '庙' && DIZHI[moonPos] === '子') pushGeju('水澄桂萼', '太阴' + DIZHI[moonPos] + '宫庙旺' + (moonPos === ming ? '坐命' : '照命三方'));
|
|
228
|
+
// 明珠出海:太阴在未(位置 5)庙(同上:坐命/三方)
|
|
229
|
+
if (moonInKey && effBrightness['太阴'] === '庙' && DIZHI[moonPos] === '未') pushGeju('明珠出海', '太阴' + DIZHI[moonPos] + '宫庙旺' + (moonPos === ming ? '坐命' : '照命三方'));
|
|
230
|
+
// 日照雷门:太阳在卯(位置 1)庙旺 + 昼生
|
|
231
|
+
const sunPos = zwStars['太阳'];
|
|
232
|
+
if (sunPos !== undefined && DIZHI[sunPos] === '卯' && effBrightness['太阳'] !== '陷' && effBrightness['太阳'] !== '平') pushGeju('日照雷门', '太阳坐卯宫' + effBrightness['太阳'] + ',' + (dayNight === 'day' ? '昼生' : '夜生') + '人');
|
|
233
|
+
// 日月并明:太阳庙旺于卯辰巳 且 太阴庙旺于酉戌亥
|
|
234
|
+
const sunGood = sunPos !== undefined && ['卯', '辰', '巳'].includes(DIZHI[sunPos]) && effBrightness['太阳'] !== '陷' && effBrightness['太阳'] !== '平';
|
|
235
|
+
const moonGood = moonPos !== undefined && ['酉', '戌', '亥'].includes(DIZHI[moonPos]) && effBrightness['太阴'] !== '陷' && effBrightness['太阴'] !== '平';
|
|
236
|
+
if (sunGood && moonGood) pushGeju('日月并明', '太阳' + DIZHI[sunPos] + effBrightness['太阳'] + '、太阴' + DIZHI[moonPos] + effBrightness['太阴'] + '皆得地');
|
|
237
|
+
|
|
238
|
+
/* 4.1 空宫借对宫(修正反馈:空宫须借对宫主星看)——十二宫逐一输出所借主星 */
|
|
239
|
+
const borrowedStars: Record<number, string[]> = {};
|
|
240
|
+
for (let i = 0; i < 12; i++) {
|
|
241
|
+
const p = palaces[i];
|
|
242
|
+
const own = Object.keys(zwStars).filter(s => zwStars[s] === p);
|
|
243
|
+
if (own.length === 0) {
|
|
244
|
+
const opp = mod(p + 6, 12);
|
|
245
|
+
borrowedStars[i] = Object.keys(zwStars).filter(s => zwStars[s] === opp);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
194
248
|
|
|
195
249
|
/* ===== 大限与流年(原逻辑保留) ===== */
|
|
196
250
|
const JU_AGE: Record<string, number> = { 二: 2, 三: 3, 四: 4, 五: 5, 六: 6 };
|
|
@@ -214,5 +268,5 @@ export function ziweiCalc(input: ZiweiInput): ZiweiResult {
|
|
|
214
268
|
const liunianPalaceName = PALACE_NAMES[Object.keys(palaces).find(k => palaces[Number(k)] === liunianIdx) ? Number(Object.keys(palaces).find(k => palaces[Number(k)] === liunianIdx)) : 0];
|
|
215
269
|
const liunianStars = Object.keys(zwStars).filter(s => zwStars[s] === liunianIdx);
|
|
216
270
|
|
|
217
|
-
return { ming, shen, zwPos, zwStars, fuStars, palaces, juName, mingGZ, nayin, correctedHour, dayun, curDayunIdx, nominalAge, liunianIdx, liunianPalaceName, liunianStars, startAge, forward, sihua, sihuaPos, brightness, geju };
|
|
271
|
+
return { ming, shen, zwPos, zwStars, fuStars, palaces, juName, mingGZ, nayin, correctedHour, dayun, curDayunIdx, nominalAge, liunianIdx, liunianPalaceName, liunianStars, startAge, forward, sihua, sihuaPos, brightness, geju, dayNight, effBrightness, borrowedStars };
|
|
218
272
|
}
|
package/shared/core/types.ts
CHANGED
|
@@ -87,8 +87,12 @@ export interface ZiweiResult {
|
|
|
87
87
|
fuStars: Record<string, number>; // 辅星位置(0=寅起)
|
|
88
88
|
sihua: { lu: string; quan: string; ke: string; ji: string }; // 生年四化星名
|
|
89
89
|
sihuaPos: { lu?: number; quan?: number; ke?: number; ji?: number }; // 四化落宫位
|
|
90
|
-
brightness: Record<string, string>; // 十四主星亮度('庙'|'旺'|'得'|'利'|'平'|'陷'
|
|
90
|
+
brightness: Record<string, string>; // 十四主星亮度('庙'|'旺'|'得'|'利'|'平'|'陷'|'不'(不得地))
|
|
91
91
|
geju: { key: string; name: string; ji: '吉' | '凶' | '平'; desc: string; why: string }[]; // 格局
|
|
92
|
+
// ─── 修正层(2026-09-05 算法边界反馈)───
|
|
93
|
+
dayNight?: 'day' | 'night'; // 昼生/夜生(按生时:卯~申为昼,酉~寅为夜;时辰序 0=子)
|
|
94
|
+
effBrightness?: Record<string, string>; // 昼夜调整后有效亮度(太阳喜昼、太阴喜夜)
|
|
95
|
+
borrowedStars?: Record<number, string[]>; // 空宫借对宫主星(十二宫位 → 所借主星)
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
// 奇门输入输出
|
|
@@ -97,12 +101,12 @@ export interface QimenResult {
|
|
|
97
101
|
yin: boolean; ju: number; jqName: string;
|
|
98
102
|
dayGZ: string; hourGZ: string;
|
|
99
103
|
xunShou: string; xunshouName: string;
|
|
100
|
-
zfStar: string; zsMen: string; zfPalace: number;
|
|
104
|
+
zfStar: string; zsMen: string; zfPalace: number; // 值符星/值使门/值符转后落宫(入中寄坤=2)
|
|
101
105
|
pan: Record<number, { yi: string; men: string; star: string }>;
|
|
102
|
-
// ─── 补齐层(2026-08-20
|
|
103
|
-
zsPalace: number; //
|
|
104
|
-
tianYi: Record<number, string>; //
|
|
105
|
-
shen: Record<number, string>; //
|
|
106
|
+
// ─── 补齐层(2026-08-20;2026-09 起转盘五层对齐拆补权威口径)───
|
|
107
|
+
zsPalace: number; // 值使门飞落宫(入中寄坤=2)
|
|
108
|
+
tianYi: Record<number, string>; // 天盘奇仪(地盘旋转,符首→时干宫;中宫原地盘干)
|
|
109
|
+
shen: Record<number, string>; // 八神布宫(阳顺阴逆,值符神落时干宫;阳用勾陈朱雀、阴用白虎玄武)
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
// 梅花输入输出
|
|
@@ -40,7 +40,7 @@ export function XiaoliurenPanel({ onDivine }: PanelProps) {
|
|
|
40
40
|
</div>
|
|
41
41
|
)}
|
|
42
42
|
<div className="field"><label htmlFor="xlr-h">时(时辰序)</label>
|
|
43
|
-
<SongSelect id="xlr-h" value={String(h)} options={['子(
|
|
43
|
+
<SongSelect id="xlr-h" value={String(h)} options={['子(0)', '丑(1)', '寅(2)', '卯(3)', '辰(4)', '巳(5)', '午(6)', '未(7)', '申(8)', '酉(9)', '戌(10)', '亥(11)'].map((t, i) => ({ value: String(i), label: t }))} onChange={v => setH(Number(v))} />
|
|
44
44
|
</div>
|
|
45
45
|
{mode === 'num' && (
|
|
46
46
|
<div className="field"><label htmlFor="xlr-n3">三数</label><input className="input-line" type="number" id="xlr-n3" min={1} max={12} value={n3} onChange={e => setN3(Number(e.target.value))} /></div>
|
package/src/pages/DemoPage.tsx
CHANGED
|
@@ -84,7 +84,7 @@ export default function DemoPage() {
|
|
|
84
84
|
case 'meihua': return () => meihuaCalc({ mode: 'number', n1, n2, n3, now: new Date() } as any);
|
|
85
85
|
case 'liuyao': return () => liuyaoCalc(undefined, { y, m, d });
|
|
86
86
|
case 'liuren': return () => liurenCalc(new Date(y, m - 1, d, hour, 0));
|
|
87
|
-
case 'xiaoliuren': return () => xiaoliurenCalc('time', m, d, Math.floor((hour % 24) / 2), n1, n2, n3);
|
|
87
|
+
case 'xiaoliuren': return () => xiaoliurenCalc('time', m, d, Math.floor(((hour % 24) + 1) % 24 / 2), n1, n2, n3);
|
|
88
88
|
case 'tarot': return () => {
|
|
89
89
|
const spread = allTarotSpreads().find((x: any) => x.id === 'three') || allTarotSpreads()[0];
|
|
90
90
|
return { spread, cards: tarotDraw(3) };
|
package/src/services/api.ts
CHANGED
|
@@ -264,7 +264,24 @@ export async function apiDivine(username: string, artId: string, inputs: unknown
|
|
|
264
264
|
try { const e = await res.json(); msg = e.message || e.error || msg; } catch { /* ignore */ }
|
|
265
265
|
throw new Error(msg);
|
|
266
266
|
}
|
|
267
|
-
|
|
267
|
+
const data = await res.json();
|
|
268
|
+
// L-NEW1 闭环:后端在「本次新建占位账号」时下发 claimToken(仅此一次),
|
|
269
|
+
// 保存到本地,供之后在 app 内注册时升级该占位账号(否则注册接口拒绝、拿不到云同步 token)
|
|
270
|
+
if (data?.claimToken) saveClaimToken(username, String(data.claimToken));
|
|
271
|
+
return data;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const CLAIM_KEY = (name: string) => 'guanwei_claim_' + name;
|
|
275
|
+
|
|
276
|
+
/** 保存/读取占位账号认领凭据(仅本地持有,随注册一次性使用) */
|
|
277
|
+
export function saveClaimToken(username: string, token: string): void {
|
|
278
|
+
try { localStorage.setItem(CLAIM_KEY(username), token); } catch { /* ignore */ }
|
|
279
|
+
}
|
|
280
|
+
export function claimTokenOf(username: string): string {
|
|
281
|
+
try { return localStorage.getItem(CLAIM_KEY(username)) || ''; } catch { return ''; }
|
|
282
|
+
}
|
|
283
|
+
export function clearClaimToken(username: string): void {
|
|
284
|
+
try { localStorage.removeItem(CLAIM_KEY(username)); } catch { /* ignore */ }
|
|
268
285
|
}
|
|
269
286
|
|
|
270
287
|
export interface DivineHistoryItem {
|
package/src/utils/userStore.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// 本地用户体系(演示级):注册/登录/会话/出生档案
|
|
2
2
|
// 注意:仅本地存储(localStorage),密码为演示级哈希,不适用于生产环境
|
|
3
3
|
import type { GeoLocation } from '@core/types';
|
|
4
|
+
import { claimTokenOf, clearClaimToken } from '../services/api';
|
|
4
5
|
|
|
5
6
|
export interface UserProfile {
|
|
6
7
|
birthDate: string; // YYYY-MM-DD(公历)
|
|
@@ -142,13 +143,16 @@ async function fetchServerToken(username: string, password: string): Promise<voi
|
|
|
142
143
|
body: JSON.stringify({ username, password }),
|
|
143
144
|
});
|
|
144
145
|
if (!res.ok) {
|
|
145
|
-
// 后端无此用户 →
|
|
146
|
+
// 后端无此用户 → 注册;若该名号已被「起占自动建档」占位,须携带建档时下发的 claimToken 方可升级
|
|
147
|
+
// (claimToken 由起占响应下发并由 services/api 落地本地,见 L-NEW1 闭环)
|
|
148
|
+
const claimToken = claimTokenOf(username);
|
|
146
149
|
res = await fetch(API + '/register', {
|
|
147
150
|
method: 'POST',
|
|
148
151
|
headers: { 'Content-Type': 'application/json' },
|
|
149
|
-
body: JSON.stringify({ username, password }),
|
|
152
|
+
body: JSON.stringify({ username, password, ...(claimToken ? { claimToken } : {}) }),
|
|
150
153
|
});
|
|
151
154
|
if (!res.ok) return;
|
|
155
|
+
clearClaimToken(username); // 一次性凭据,成功升级后即弃
|
|
152
156
|
}
|
|
153
157
|
const data = await res.json();
|
|
154
158
|
if (data.token) {
|
package/vite.config.ts
CHANGED
|
@@ -3,17 +3,21 @@ import react from '@vitejs/plugin-react'
|
|
|
3
3
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
4
4
|
|
|
5
5
|
// https://vite.dev/config/
|
|
6
|
+
// 后端地址:跟随 CLI 的 PORT/API_PORT(`guanwei start --api 4000` 时前端代理需同步)
|
|
7
|
+
const API_TARGET = `http://localhost:${process.env.API_PORT || process.env.PORT || 3018}`;
|
|
8
|
+
|
|
6
9
|
export default defineConfig({
|
|
7
10
|
test: {
|
|
8
11
|
environment: 'jsdom',
|
|
9
12
|
},
|
|
10
13
|
build: {
|
|
11
|
-
sourcemap
|
|
14
|
+
// 生产不产出 sourcemap(原 'hidden' 仍生成 .map 文件,随 npm 包分发且可被公开访问 → 源码泄漏)
|
|
15
|
+
sourcemap: false,
|
|
12
16
|
},
|
|
13
17
|
server: {
|
|
14
18
|
proxy: {
|
|
15
19
|
'/api': {
|
|
16
|
-
target:
|
|
20
|
+
target: API_TARGET,
|
|
17
21
|
changeOrigin: true,
|
|
18
22
|
},
|
|
19
23
|
},
|
|
@@ -22,7 +26,7 @@ export default defineConfig({
|
|
|
22
26
|
preview: {
|
|
23
27
|
proxy: {
|
|
24
28
|
'/api': {
|
|
25
|
-
target:
|
|
29
|
+
target: API_TARGET,
|
|
26
30
|
changeOrigin: true,
|
|
27
31
|
},
|
|
28
32
|
},
|