@openephemeris/mcp-server 3.17.0 → 3.20.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 +77 -0
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/dist/backend/client.d.ts +9 -0
- package/dist/backend/client.js +32 -5
- package/dist/event-store.d.ts +11 -0
- package/dist/event-store.js +61 -0
- package/dist/index.js +12 -11
- package/dist/oauth/session-utils.d.ts +59 -0
- package/dist/oauth/session-utils.js +110 -0
- package/dist/server-sse.d.ts +7 -1
- package/dist/server-sse.js +223 -127
- package/dist/tools/apps/bi-wheel-app.js +8 -6
- package/dist/tools/apps/chart-wheel-app.js +36 -51
- package/dist/tools/dev.js +1 -1
- package/dist/tools/index.d.ts +25 -0
- package/dist/tools/index.js +33 -0
- package/dist/tools/output-schemas.d.ts +1 -1
- package/dist/tools/output-schemas.js +1 -1
- package/dist/tools/specialized/acg.js +6 -2
- package/dist/tools/specialized/progressed.js +3 -1
- package/dist/ui/bi-wheel.html +5 -2
- package/dist/ui/bodygraph.html +30 -3
- package/dist/ui/chart-wheel.html +20 -22
- package/dist/ui/moon-phase.html +39 -32
- package/package.json +8 -4
- package/dist/tools/apps/bazi-app.d.ts +0 -23
- package/dist/tools/apps/bazi-app.js +0 -226
- package/dist/tools/apps/transit-timeline-app.d.ts +0 -20
- package/dist/tools/apps/transit-timeline-app.js +0 -295
- package/dist/tools/apps/vedic-chart-app.d.ts +0 -17
- package/dist/tools/apps/vedic-chart-app.js +0 -228
- package/dist/ui/bazi.html +0 -213
- package/dist/ui/transit-timeline.html +0 -6874
- package/dist/ui/vedic-chart.html +0 -210
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vedic-chart-app.ts — MCP App tool registration for the Vedic Jyotish Chart Explorer.
|
|
3
|
-
*
|
|
4
|
-
* Registers 1 tool:
|
|
5
|
-
* • explore_vedic_chart — primary entry point [model + app visible]
|
|
6
|
-
* Calls POST /vedic/chart and returns a data payload + UI resource URI
|
|
7
|
-
* so Claude Desktop can render the interactive South Indian Rashi grid.
|
|
8
|
-
*
|
|
9
|
-
* Also exports resource helpers (getVedicChartBundle, etc.) for use in
|
|
10
|
-
* server-sse.ts resource listing and reading.
|
|
11
|
-
*/
|
|
12
|
-
import fs from "node:fs";
|
|
13
|
-
import path from "node:path";
|
|
14
|
-
import { fileURLToPath } from "node:url";
|
|
15
|
-
import { registerTool, SERVER_VERSION } from "../index.js";
|
|
16
|
-
import { getActiveClient } from "../../backend/client.js";
|
|
17
|
-
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
18
|
-
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
19
|
-
export const VEDIC_CHART_RESOURCE_URI = "ui://openephemeris/vedic-chart";
|
|
20
|
-
export const VEDIC_CHART_MIME_TYPE = "text/html;profile=mcp-app";
|
|
21
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
22
|
-
const BUNDLE_PATHS = [
|
|
23
|
-
path.resolve(here, "..", "..", "..", "dist", "ui", "vedic-chart.html"),
|
|
24
|
-
];
|
|
25
|
-
function findBundlePath() {
|
|
26
|
-
for (const p of BUNDLE_PATHS) {
|
|
27
|
-
if (fs.existsSync(p))
|
|
28
|
-
return p;
|
|
29
|
-
}
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
let cachedBundle = null;
|
|
33
|
-
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
34
|
-
export function getVedicChartBundle() {
|
|
35
|
-
if (cachedBundle)
|
|
36
|
-
return cachedBundle;
|
|
37
|
-
const bundlePath = findBundlePath();
|
|
38
|
-
if (!bundlePath)
|
|
39
|
-
return null;
|
|
40
|
-
try {
|
|
41
|
-
cachedBundle = fs.readFileSync(bundlePath, "utf-8");
|
|
42
|
-
return cachedBundle;
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
/** Reset cache (useful in dev watch mode or tests). */
|
|
49
|
-
export function clearVedicChartBundleCache() {
|
|
50
|
-
cachedBundle = null;
|
|
51
|
-
}
|
|
52
|
-
function parseVedicArgs(args) {
|
|
53
|
-
const { datetime, latitude, longitude, ayanamsa } = args;
|
|
54
|
-
if (!datetime) {
|
|
55
|
-
throw new Error("datetime is required. Provide an ISO 8601 datetime in UTC, " +
|
|
56
|
-
"e.g. datetime='1987-07-15T14:30:00Z'.");
|
|
57
|
-
}
|
|
58
|
-
if (latitude == null || longitude == null) {
|
|
59
|
-
throw new Error("latitude and longitude are required for Vedic chart calculation. " +
|
|
60
|
-
"Example: latitude=28.6, longitude=77.2 (New Delhi).");
|
|
61
|
-
}
|
|
62
|
-
return { datetime, latitude, longitude, ayanamsa: ayanamsa || undefined };
|
|
63
|
-
}
|
|
64
|
-
// ── Summary builder ──────────────────────────────────────────────────────────
|
|
65
|
-
// Convert a sidereal longitude (0–360°) to the Western sign name
|
|
66
|
-
function lonToSignName(lon) {
|
|
67
|
-
const SIGNS = [
|
|
68
|
-
"Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
|
|
69
|
-
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces",
|
|
70
|
-
];
|
|
71
|
-
const idx = Math.floor(((lon % 360) + 360) % 360 / 30) % 12;
|
|
72
|
-
return SIGNS[idx];
|
|
73
|
-
}
|
|
74
|
-
function buildVedicSummary(data) {
|
|
75
|
-
const planets = data.planets || [];
|
|
76
|
-
const metadata = data.metadata || {};
|
|
77
|
-
// lagna is a degree float from the backend — convert to sign name
|
|
78
|
-
const lagnaSign = typeof metadata.lagna === "number"
|
|
79
|
-
? lonToSignName(metadata.lagna)
|
|
80
|
-
: metadata.lagna || "unknown";
|
|
81
|
-
// Backend returns "ayanamsha" (with extra h) — normalise
|
|
82
|
-
const ayanamsa = metadata.ayanamsa || metadata.ayanamsha || "Lahiri";
|
|
83
|
-
const ayanamsaVal = metadata.ayanamsa_value != null
|
|
84
|
-
? " (" + metadata.ayanamsa_value.toFixed(2) + "°)"
|
|
85
|
-
: metadata.correction != null
|
|
86
|
-
? " (" + metadata.correction.toFixed(2) + "°)"
|
|
87
|
-
: "";
|
|
88
|
-
let summary = "**Vedic Jyotish Chart** — Lagna: **" + lagnaSign + "** · Ayanamsa: " +
|
|
89
|
-
ayanamsa + ayanamsaVal + "\n\n";
|
|
90
|
-
// Planet placement table
|
|
91
|
-
if (planets.length > 0) {
|
|
92
|
-
summary += "| Planet | Rashi | Degree | Nakshatra | Pada |\n";
|
|
93
|
-
summary += "|--------|-------|--------|-----------|------|\n";
|
|
94
|
-
for (const p of planets) {
|
|
95
|
-
const retroMark = p.is_retrograde ? " ℞" : "";
|
|
96
|
-
summary +=
|
|
97
|
-
"| " + capFirst(String(p.planet)) + retroMark +
|
|
98
|
-
" | " + (p.rashi_western || p.rashi || "?") +
|
|
99
|
-
" | " + (typeof p.rashi_degree === "number" ? p.rashi_degree.toFixed(2) + "°" : "?") +
|
|
100
|
-
" | " + (p.nakshatra?.name || "?") +
|
|
101
|
-
" | " + (p.nakshatra?.pada || "?") +
|
|
102
|
-
" |\n";
|
|
103
|
-
}
|
|
104
|
-
summary += "\n";
|
|
105
|
-
}
|
|
106
|
-
summary += "Click on any Rashi cell to explore the planets placed there.";
|
|
107
|
-
return summary;
|
|
108
|
-
}
|
|
109
|
-
function capFirst(s) {
|
|
110
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
111
|
-
}
|
|
112
|
-
// ── Tool: explore_vedic_chart ─────────────────────────────────────────────────
|
|
113
|
-
registerTool({
|
|
114
|
-
name: "explore_vedic_chart",
|
|
115
|
-
description: "Generate an interactive Vedic Jyotish (South Indian) Rashi chart visualization.\n\n" +
|
|
116
|
-
"Renders a 4×4 fixed-sign grid with:\n" +
|
|
117
|
-
" • All nine Jyotish planets (Sun through Ketu) placed in their Rashi\n" +
|
|
118
|
-
" • Lagna (Ascendant) cell marked with a gold diagonal\n" +
|
|
119
|
-
" • Sanskrit/Devanagari sign labels toggle\n" +
|
|
120
|
-
" • Click any Rashi cell → detailed planet info drawer\n" +
|
|
121
|
-
" (degree, Nakshatra, Pada, lord, Navamsa sign, dignity)\n" +
|
|
122
|
-
" • Ask Claude buttons for Lagna, Moon/Nakshatra, and full chart interpretation\n" +
|
|
123
|
-
" • Ayanamsa system displayed (Lahiri by default)\n\n" +
|
|
124
|
-
"CREDIT COST: 1 credit.\n\n" +
|
|
125
|
-
"Use this for a rich, interactive Vedic chart experience in MCP Apps-capable hosts " +
|
|
126
|
-
"(Claude Desktop). Falls back to a markdown table summary in other hosts.",
|
|
127
|
-
inputSchema: {
|
|
128
|
-
type: "object",
|
|
129
|
-
properties: {
|
|
130
|
-
datetime: {
|
|
131
|
-
type: "string",
|
|
132
|
-
description: "Birth date and time as ISO 8601, e.g. '1987-07-15T14:30:00Z'. " +
|
|
133
|
-
"Always include time when known — it determines the Lagna (Ascendant).",
|
|
134
|
-
},
|
|
135
|
-
latitude: {
|
|
136
|
-
type: "number",
|
|
137
|
-
description: "Birth latitude in decimal degrees, e.g. 28.6 for New Delhi.",
|
|
138
|
-
},
|
|
139
|
-
longitude: {
|
|
140
|
-
type: "number",
|
|
141
|
-
description: "Birth longitude in decimal degrees, e.g. 77.2 for New Delhi.",
|
|
142
|
-
},
|
|
143
|
-
ayanamsa: {
|
|
144
|
-
type: "string",
|
|
145
|
-
enum: ["lahiri", "fagan_bradley", "krishnamurti", "raman", "yukteshwar"],
|
|
146
|
-
description: "Ayanamsa system for sidereal calculation. " +
|
|
147
|
-
"Options: 'lahiri' (default, most common), 'raman', 'krishnamurti', 'fagan_bradley', 'yukteshwar'.",
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
required: ["datetime", "latitude", "longitude"],
|
|
151
|
-
additionalProperties: false,
|
|
152
|
-
},
|
|
153
|
-
outputSchema: OUTPUT_SCHEMA_JSON,
|
|
154
|
-
annotations: {
|
|
155
|
-
title: "Interactive Vedic Jyotish Chart",
|
|
156
|
-
readOnlyHint: true,
|
|
157
|
-
destructiveHint: false,
|
|
158
|
-
idempotentHint: true,
|
|
159
|
-
openWorldHint: false,
|
|
160
|
-
},
|
|
161
|
-
_meta: {
|
|
162
|
-
ui: {
|
|
163
|
-
resourceUri: VEDIC_CHART_RESOURCE_URI,
|
|
164
|
-
visibility: ["model", "app"],
|
|
165
|
-
},
|
|
166
|
-
},
|
|
167
|
-
handler: async (args) => {
|
|
168
|
-
const { datetime, latitude, longitude, ayanamsa } = parseVedicArgs(args);
|
|
169
|
-
const client = getActiveClient();
|
|
170
|
-
// Backend field is datetime_utc (matches vedic.ts specialized tool)
|
|
171
|
-
const body = {
|
|
172
|
-
datetime_utc: datetime,
|
|
173
|
-
latitude,
|
|
174
|
-
longitude,
|
|
175
|
-
};
|
|
176
|
-
if (ayanamsa)
|
|
177
|
-
body.ayanamsa = ayanamsa;
|
|
178
|
-
const result = await client.request("POST", "/vedic/chart", { data: body });
|
|
179
|
-
const rawMeta = result.metadata || {};
|
|
180
|
-
// Backend returns lagna as a degree float (e.g. 213.4) but the iframe
|
|
181
|
-
// expects a sign name string (e.g. "Scorpio") for cell matching.
|
|
182
|
-
const lagnaRaw = rawMeta.lagna;
|
|
183
|
-
const lagnaSign = typeof lagnaRaw === "number"
|
|
184
|
-
? lonToSignName(lagnaRaw)
|
|
185
|
-
: lagnaRaw || "";
|
|
186
|
-
// Backend returns "ayanamsha" (extra h) — normalise to "ayanamsa".
|
|
187
|
-
const ayanamsaName = rawMeta.ayanamsa || rawMeta.ayanamsha || "Lahiri";
|
|
188
|
-
const normalizedMeta = {
|
|
189
|
-
...rawMeta,
|
|
190
|
-
lagna: lagnaSign,
|
|
191
|
-
ayanamsa: ayanamsaName,
|
|
192
|
-
// Expose correction as ayanamsa_value so the iframe can show the degree
|
|
193
|
-
ayanamsa_value: rawMeta.ayanamsa_value ?? rawMeta.correction ?? null,
|
|
194
|
-
};
|
|
195
|
-
// Build a Set from the retrograde_planets list the Go handler populated.
|
|
196
|
-
const retrogradeList = Array.isArray(rawMeta.retrograde_planets)
|
|
197
|
-
? rawMeta.retrograde_planets
|
|
198
|
-
: [];
|
|
199
|
-
const retrogradeSet = new Set(retrogradeList);
|
|
200
|
-
const uiPayload = {
|
|
201
|
-
// Stamp is_retrograde on each planet using the retrograde_planets list
|
|
202
|
-
// from metadata — the Go struct has no such field, so it lives in metadata.
|
|
203
|
-
planets: (result.planets || []).map((p) => ({
|
|
204
|
-
...p,
|
|
205
|
-
is_retrograde: retrogradeSet.has(String(p.planet)),
|
|
206
|
-
})),
|
|
207
|
-
metadata: normalizedMeta,
|
|
208
|
-
server_version: SERVER_VERSION,
|
|
209
|
-
};
|
|
210
|
-
const summary = buildVedicSummary(uiPayload);
|
|
211
|
-
const bundleAvailable = Boolean(getVedicChartBundle());
|
|
212
|
-
if (bundleAvailable) {
|
|
213
|
-
return {
|
|
214
|
-
content: [
|
|
215
|
-
{ type: "text", text: summary },
|
|
216
|
-
// Second text block is injected as window.__VEDIC_CHART_DATA__ by ext-apps SDK
|
|
217
|
-
{ type: "text", text: JSON.stringify(uiPayload) },
|
|
218
|
-
],
|
|
219
|
-
_meta: {
|
|
220
|
-
"ui/resourceUri": VEDIC_CHART_RESOURCE_URI,
|
|
221
|
-
ui: { resourceUri: VEDIC_CHART_RESOURCE_URI },
|
|
222
|
-
},
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
// Fallback: text-only table
|
|
226
|
-
return { content: [{ type: "text", text: summary }] };
|
|
227
|
-
},
|
|
228
|
-
});
|
package/dist/ui/bazi.html
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<meta name="color-scheme" content="dark light" />
|
|
7
|
-
<title>BaZi Four Pillars Explorer</title>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<style>*,:before,:after{box-sizing:border-box;margin:0;padding:0}:root{--bg-primary:#090b0f;--bg-secondary:#12161d;--bg-tertiary:#1c222b;--bg-hover:#272e3b;--border:#282e38;--border-subtle:#1d2229;--text-primary:#e1e5eb;--text-secondary:#9da5b1;--text-muted:#6c727b;--accent:#62b3ff;--accent-warm:#e6ac3d;--radius:8px;--radius-sm:4px;--radius-lg:12px;--wuxing-wood:#31aa40;--wuxing-fire:#f14d4c;--wuxing-earth:#ca8a10;--wuxing-metal:#9fafc8;--wuxing-water:#0099e0;--wuxing-wood-bg:#1b451e;--wuxing-fire-bg:#65201e;--wuxing-earth-bg:#583c10;--wuxing-metal-bg:#3c434d;--wuxing-water-bg:#003f60;--dm-border:#d29922;--dm-bg:#201a10;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}@supports (color:color(display-p3 0 0 0)){:root{--bg-primary:color(display-p3 .036047 .0438664 .059078);--bg-secondary:color(display-p3 .0739679 .0866504 .111186);--bg-tertiary:color(display-p3 .114361 .13221 .166818);--bg-hover:color(display-p3 .15679 .180114 .225406);--border:color(display-p3 .161376 .180145 .216325);--border-subtle:color(display-p3 .118728 .13221 .158123);--text-primary:color(display-p3 .883958 .896627 .920543);--text-secondary:color(display-p3 .622745 .646433 .6914);--text-muted:color(display-p3 .429297 .445909 .477439);--accent:color(display-p3 .446063 .694439 1.01077);--accent-warm:color(display-p3 .866978 .684443 .324483);--wuxing-wood:color(display-p3 .343741 .657851 .307102);--wuxing-fire:color(display-p3 .872583 .352089 .325751);--wuxing-earth:color(display-p3 .754604 .550516 .200367);--wuxing-metal:color(display-p3 .636614 .68404 .77495);--wuxing-water:color(display-p3 .226818 .589506 .875825);--wuxing-wood-bg:color(display-p3 .150499 .267148 .135899);--wuxing-fire-bg:color(display-p3 .36387 .143128 .129405);--wuxing-earth-bg:color(display-p3 .328547 .240912 .0972974);--wuxing-metal-bg:color(display-p3 .240898 .260909 .299258);--wuxing-water-bg:color(display-p3 .0921333 .242221 .364185);--dm-border:color(display-p3 .789908 .60997 .245434);--dm-bg:color(display-p3 .119765 .101379 .0671137)}}@supports (color:lab(0% 0 0)){:root{--bg-primary:lab(3.02674% -.179462 -2.15476);--bg-secondary:lab(7.16596% -.441141 -5.41423);--bg-tertiary:lab(12.9118% -.60384 -7.27841);--bg-hover:lab(18.6882% -.727877 -9.08878);--border:lab(18.7165% -.689313 -7.30941);--border-subtle:lab(12.9391% -.548743 -5.49436);--text-primary:lab(90.6878% -.517368 -3.73452);--text-secondary:lab(67.45% -.932217 -7.41489);--text-muted:lab(47.7476% -.701487 -5.56231);--accent:lab(70.4043% -7.21234 -50.7672);--accent-warm:lab(74.5248% 14.3487 62.5064);--wuxing-wood:lab(61.5358% -50.6384 43.17);--wuxing-fire:lab(57.3944% 63.124 38.0626);--wuxing-earth:lab(62.7263% 19.0613 64.9727);--wuxing-metal:lab(70.8424% -1.5474 -14.6858);--wuxing-water:lab(59.1191% -14.8305 -49.6808);--wuxing-wood-bg:lab(25.5679% -22.4482 18.6532);--wuxing-fire-bg:lab(23.6033% 31.5073 18.7032);--wuxing-earth-bg:lab(28.0231% 9.19801 30.8603);--wuxing-metal-bg:lab(28.0014% -.778109 -7.34471);--wuxing-water-bg:lab(24.4811% -7.8918 -24.9024);--dm-border:lab(67.5362% 14.8294 64.5914);--dm-bg:lab(9.55197% 1.60985 7.31485)}}@media (prefers-color-scheme:light){:root{--bg-primary:#f3f5f9;--bg-secondary:#e7ebf2;--bg-tertiary:#d8dee8;--bg-hover:#d0d8e5;--border:#bdc5d1;--border-subtle:#d2d8e2;--text-primary:#0f1216;--text-secondary:#414853;--text-muted:#6c727b;--accent:#0065b2;--accent-warm:#966800;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--wuxing-wood:#005f0e;--wuxing-fire:#a20519;--wuxing-earth:#805300;--wuxing-metal:#48566c;--wuxing-water:#005380;--wuxing-wood-bg:#c0e3c0;--wuxing-fire-bg:#fdc9c4;--wuxing-earth-bg:#f2daba;--wuxing-metal-bg:#d6dfec;--wuxing-water-bg:#b4defc;--dm-border:#966800;--dm-bg:#f6ede0}@supports (color:color(display-p3 0 0 0)){:root{--bg-primary:color(display-p3 .95471 .961142 .973263);--bg-secondary:color(display-p3 .909797 .922535 .946581);--bg-tertiary:color(display-p3 .852455 .871315 .906983);--bg-hover:color(display-p3 .821139 .84609 .893374);--border:color(display-p3 .745559 .770059 .816515);--border-subtle:color(display-p3 .826933 .845684 .881152);--text-primary:color(display-p3 .0608605 .0691527 .0850621);--text-secondary:color(display-p3 .261513 .281801 .32064);--text-muted:color(display-p3 .429297 .445909 .477439);--accent:color(display-p3 .143802 .388951 .683672);--accent-warm:color(display-p3 .596632 .396992 -.158844);--wuxing-wood:color(display-p3 .0968244 .374385 .0683277);--wuxing-fire:color(display-p3 .580784 .119608 .128804);--wuxing-earth:color(display-p3 .489279 .326588 -.0287041);--wuxing-metal:color(display-p3 .294019 .335238 .415486);--wuxing-water:color(display-p3 -.0775243 .316124 .547443);--wuxing-wood-bg:color(display-p3 .778394 .884493 .76257);--wuxing-fire-bg:color(display-p3 .959986 .795906 .773571);--wuxing-earth-bg:color(display-p3 .93331 .858308 .743829);--wuxing-metal-bg:color(display-p3 .84663 .871726 .919277);--wuxing-water-bg:color(display-p3 .739548 .864306 .975015);--dm-border:color(display-p3 .596632 .396992 -.158844);--dm-bg:color(display-p3 .957692 .931855 .88349)}}@supports (color:lab(0% 0 0)){:root{--bg-primary:lab(96.5044% -.267148 -1.87216);--bg-secondary:lab(93.0079% -.518024 -3.73493);--bg-tertiary:lab(88.3503% -.749856 -5.58736);--bg-hover:lab(86.0117% -.963002 -7.43048);--border:lab(79.0511% -.952899 -7.42528);--border-subtle:lab(86.0302% -.748128 -5.58645);--text-primary:lab(5.23796% -.285208 -3.0582);--text-secondary:lab(30.3224% -.794604 -7.35167);--text-muted:lab(47.7476% -.701487 -5.56231);--accent:lab(41.1205% -1.70796 -50.1423);--accent-warm:lab(47.6194% 20.1868 104.51);--wuxing-wood:lab(34.5429% -45.3762 42.1829);--wuxing-fire:lab(34.3495% 57.1812 37.8813);--wuxing-earth:lab(39.4811% 17.4358 64.8795);--wuxing-metal:lab(36.0172% -1.09252 -14.5181);--wuxing-water:lab(32.2784% -8.65509 -43.065);--wuxing-wood-bg:lab(86.8562% -16.7675 13.1583);--wuxing-fire-bg:lab(85.5193% 18.485 10.0423);--wuxing-earth-bg:lab(88.4503% 4.9783 19.0112);--wuxing-metal-bg:lab(88.3319% -.966102 -7.43206);--wuxing-water-bg:lab(86.1283% -8.87641 -19.3614);--dm-border:lab(47.6194% 20.1868 104.51);--dm-bg:lab(94.2538% 1.22291 7.5882)}}}html,body{background:var(--bg-primary);width:100%;height:100%;color:var(--text-primary);font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:13px;line-height:1.5;overflow:hidden}body{flex-direction:column;display:flex}#app{flex-direction:column;flex:1;display:flex;overflow:hidden}#loading-state{color:var(--text-secondary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;display:flex}#loading-state[hidden]{display:none}.oe-loader{width:48px;height:48px;animation:1.2s linear infinite spin}.oe-loader circle{fill:none;stroke:var(--accent);stroke-width:3px;stroke-dasharray:200;stroke-dashoffset:80px;stroke-linecap:round}@keyframes spin{to{transform:rotate(360deg)}}.chart-status{background:var(--bg-secondary);border-top:1px solid var(--border-subtle);color:var(--text-muted);opacity:0;z-index:50;padding:6px 14px;font-size:11px;transition:opacity .2s,transform .2s;position:fixed;bottom:0;left:0;right:0;transform:translateY(100%)}.chart-status.visible{opacity:1;transform:translateY(0)}#bazi-container{flex-direction:column;flex:1;gap:16px;padding:16px;display:flex;overflow-y:auto}#bazi-container[hidden]{display:none}.bazi-pillars{grid-template-columns:repeat(4,1fr);gap:8px;animation:.6s ease-out bazi-fade-in;display:grid}@keyframes bazi-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.bazi-pillar{border:1px solid var(--border-subtle);border-radius:var(--radius);background:var(--bg-secondary);cursor:pointer;flex-direction:column;transition:border-color .15s,box-shadow .15s,transform .15s;display:flex;overflow:hidden}.bazi-pillar:hover{border-color:var(--border);transform:translateY(-1px);box-shadow:0 2px 12px rgba(0,0,0,.1);box-shadow:0 2px 12px color(display-p3 0 0 0/.1);box-shadow:0 2px 12px lab(0% 0 0/.1)}.bazi-pillar--dm{border-color:var(--dm-border);background:var(--dm-bg);box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border)}.bazi-pillar--dm:hover{border-color:var(--dm-border);box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px rgba(210,153,34,.15)}@supports (color:color(display-p3 0 0 0)){.bazi-pillar--dm:hover{box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px color(display-p3 .789908 .60997 .245434/.15)}}@supports (color:lab(0% 0 0)){.bazi-pillar--dm:hover{box-shadow:inset 3px 0 0 var(--dm-border), inset -3px 0 0 var(--dm-border), 0 4px 16px lab(67.5362% 14.8294 64.5914/.15)}}.bazi-pillar-header{text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);background:var(--bg-tertiary);border-bottom:1px solid var(--border-subtle);justify-content:center;align-items:center;gap:4px;padding:6px 8px;font-size:10px;font-weight:700;display:flex}.bazi-pillar--dm .bazi-pillar-header{color:var(--dm-border)}.dm-badge{background:var(--dm-border);color:#090b0f;color:color(display-p3 .036047 .0438664 .059078);color:lab(3.02674% -.179462 -2.15476);letter-spacing:.04em;border-radius:10px;padding:1px 5px;font-size:9px;font-weight:700}@media (prefers-color-scheme:light){.dm-badge{color:#fcf8f1;color:color(display-p3 .985424 .972455 .948118);color:lab(97.7087% .579864 3.77247)}}.bazi-stem-zone{border-bottom:1px solid var(--border-subtle);flex-direction:column;align-items:center;gap:2px;padding:10px 8px;display:flex}.bazi-stem-chinese{font-size:28px;font-weight:700;line-height:1.1}.bazi-stem-name{color:var(--text-secondary);font-size:11px;font-weight:600}.bazi-stem-element{color:var(--bg-primary);border-radius:10px;padding:1px 6px;font-size:10px;font-weight:500}@media (prefers-color-scheme:light){.bazi-stem-element{color:#fff6f8;color:color(display-p3 .992746 .964982 .972458);color:lab(97.5544% 3.37881 .0330448)}}.bazi-branch-zone{border-bottom:1px solid var(--border-subtle);flex-direction:column;align-items:center;gap:2px;padding:10px 8px;display:flex}.bazi-branch-animal-emoji{font-size:22px;line-height:1.1}.bazi-branch-name{color:var(--text-secondary);font-size:11px;font-weight:600}.bazi-branch-animal{color:var(--text-muted);font-size:10px}.bazi-hidden-zone{flex-direction:column;align-items:center;gap:3px;min-height:48px;padding:6px 8px;display:flex}.bazi-hidden-label{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin-bottom:1px;font-size:9px;font-weight:600}.bazi-hidden-stems{flex-wrap:wrap;justify-content:center;gap:6px;display:flex}.bazi-hidden-stem{flex-direction:column;align-items:center;gap:1px;display:flex}.bazi-hidden-char{font-size:16px;font-weight:600;line-height:1.1}.bazi-hidden-strength{opacity:.7;border-radius:50%;width:6px;height:6px}.bazi-hidden-strength--main{opacity:1}.bazi-hidden-strength--secondary{opacity:.65}.bazi-hidden-strength--residual{opacity:.35}.bazi-ten-god-tag{background:var(--bg-hover);color:var(--text-secondary);border-radius:10px;padding:1px 5px;font-size:9px;font-weight:600}.bazi-balance{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius);flex-direction:column;gap:8px;padding:12px 14px;animation:.8s ease-out .2s both bazi-fade-in;display:flex}.bazi-balance-header{justify-content:space-between;align-items:center;display:flex}.bazi-balance-title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);font-size:11px;font-weight:700}.bazi-balance-strength{background:var(--bg-hover);color:var(--text-secondary);border-radius:10px;padding:2px 8px;font-size:11px;font-weight:600}.bazi-balance-strength--strong{color:var(--wuxing-wood)}.bazi-balance-strength--weak{color:var(--wuxing-fire)}.bazi-bar-container{border-radius:var(--radius-sm);border:1px solid var(--border-subtle);height:28px;display:flex;overflow:hidden}.bazi-bar-segment{min-width:24px;color:var(--text-primary);justify-content:center;align-items:center;font-size:10px;font-weight:700;transition:flex .4s ease-out;display:flex;position:relative;overflow:hidden}.bazi-bar-segment-label{opacity:.8;white-space:nowrap;font-size:9px}.bazi-bar-legend{flex-wrap:wrap;justify-content:center;gap:12px;display:flex}.bazi-legend-item{color:var(--text-secondary);cursor:pointer;align-items:center;gap:4px;font-size:11px;transition:color .15s;display:flex}.bazi-legend-item:hover{color:var(--text-primary)}.bazi-legend-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.bazi-legend-pct{font-variant-numeric:tabular-nums;font-weight:700}.bazi-legend-score{color:var(--text-muted);font-size:10px}.bazi-yongshen{border-radius:var(--radius-sm);background:var(--bg-tertiary);border:1px solid var(--border-subtle);color:var(--text-secondary);justify-content:center;align-items:center;gap:6px;padding:6px 12px;font-size:12px;display:flex}.bazi-yongshen-label{color:var(--text-muted);font-weight:500}.bazi-yongshen-value{font-weight:700}.bazi-drawer-overlay{z-index:60;opacity:0;background:rgba(0,0,0,.4);background:color(display-p3 0 0 0/.4);background:lab(0% 0 0/.4);transition:opacity .2s;position:fixed;top:0;bottom:0;left:0;right:0}.bazi-drawer-overlay.visible{opacity:1}.bazi-drawer{background:var(--bg-secondary);border-top:1px solid var(--border);border-radius:var(--radius-lg) var(--radius-lg) 0 0;z-index:61;max-height:60vh;padding:16px;transition:transform .25s ease-out;position:fixed;bottom:0;left:0;right:0;overflow-y:auto;transform:translateY(100%)}.bazi-drawer.visible{transform:translateY(0)}.bazi-drawer-handle{background:var(--border);border-radius:2px;width:36px;height:4px;margin:0 auto 12px}.bazi-drawer-title{align-items:center;gap:8px;margin-bottom:12px;font-size:15px;font-weight:700;display:flex}.bazi-drawer-section{margin-bottom:12px}.bazi-drawer-section-title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted);margin-bottom:6px;font-size:10px;font-weight:700}.bazi-drawer-ten-god{background:var(--bg-tertiary);border-radius:var(--radius-sm);align-items:center;gap:10px;margin-bottom:6px;padding:8px 10px;display:flex}.bazi-drawer-tg-chinese{font-size:22px;font-weight:700}.bazi-drawer-tg-info{flex-direction:column;gap:1px;display:flex}.bazi-drawer-tg-name{font-size:13px;font-weight:600}.bazi-drawer-tg-category{color:var(--text-muted);text-transform:capitalize;font-size:11px}.bazi-drawer-hidden-table{border-collapse:collapse;width:100%;font-size:12px}.bazi-drawer-hidden-table th{text-transform:uppercase;letter-spacing:.04em;color:var(--text-muted);text-align:left;border-bottom:1px solid var(--border-subtle);padding:4px 8px;font-size:10px;font-weight:700}.bazi-drawer-hidden-table td{border-bottom:1px solid var(--border-subtle);color:var(--text-secondary);padding:5px 8px}.bazi-drawer-hidden-table tr:last-child td{border-bottom:none}.bazi-actions{flex-wrap:wrap;gap:8px;animation:.8s ease-out .4s both bazi-fade-in;display:flex}.action-btn{border-radius:var(--radius);border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-secondary);cursor:pointer;align-items:center;gap:4px;padding:8px 14px;font-size:12px;font-weight:600;transition:background .15s,color .15s,box-shadow .15s;display:inline-flex}.action-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.action-btn--primary{color:#cbdfff;color:color(display-p3 .811259 .873257 .992208);color:lab(88.2011% -1.89927 -18.3428);background:linear-gradient(135deg,#1d4587,#32326d);background:linear-gradient(135deg,color(display-p3 .153533 .2659 .511983),color(display-p3 .195291 .194916 .412031));background:linear-gradient(135deg,lab(29.3399% 5.63866 -42.0206),lab(23.3003% 14.2058 -35.0966));border-color:#33548c;border-color:color(display-p3 .229049 .327581 .533696);border-color:lab(35.4848% 1.84765 -35.3079)}.action-btn--primary:hover{background:linear-gradient(135deg,#2151a1,#3d3c86);background:linear-gradient(135deg,color(display-p3 .180134 .31482 .611657),color(display-p3 .239239 .236673 .50744));background:linear-gradient(135deg,lab(34.9279% 7.15981 -48.9835),lab(28.8006% 17.5515 -42.0715));box-shadow:0 2px 12px rgba(29,69,135,.3);box-shadow:0 2px 12px color(display-p3 .153533 .2659 .511983/.3);box-shadow:0 2px 12px lab(29.3399% 5.63866 -42.0206/.3)}.error-state,.empty-state{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:32px;display:flex}.error-icon,.empty-icon{font-size:32px}.tooltip{z-index:100;border-radius:var(--radius-sm);background:var(--bg-tertiary);border:1px solid var(--border);color:var(--text-primary);pointer-events:none;opacity:0;max-width:200px;padding:6px 10px;font-size:11px;transition:opacity .15s;position:fixed}.tooltip.visible{opacity:1}@media (max-width:360px){.bazi-stem-chinese{font-size:22px}.bazi-branch-animal-emoji{font-size:18px}.bazi-hidden-char{font-size:13px}.bazi-pillar-header{padding:4px 6px;font-size:9px}#bazi-container{gap:10px;padding:10px}.bazi-pillars{gap:4px}}.chart-layer{opacity:1;transform-origin:310px 310px;animation:.5s cubic-bezier(.16,1,.3,1) both svgLayerAssemble;animation-delay:calc(var(--layer-index,0) * 80ms);transform:scale(1)}@keyframes svgLayerAssemble{0%{opacity:0;transform:scale(.97)}to{opacity:1;transform:scale(1)}}.floating-action-btn:after{content:"";background:linear-gradient(90deg,transparent,rgba(255,255,255,.2),transparent);width:50%;height:100%;animation:3s 2s infinite shimmer;position:absolute;top:0;left:-100%;transform:skew(-20deg)}@keyframes shimmer{0%{left:-100%}20%{left:200%}to{left:200%}}@keyframes slideUpFadeIn{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes slideUpFadeInPanel{0%{opacity:0;transform:translateY(12px)scale(.98)}to{opacity:1;transform:translateY(0)scale(1)}}
|
|
11
|
-
/*$vite$:1*/</style>
|
|
12
|
-
</head>
|
|
13
|
-
<body>
|
|
14
|
-
<div id="app">
|
|
15
|
-
<div id="loading-state">
|
|
16
|
-
<svg class="oe-loader" viewBox="0 0 100 100"><circle cx="50" cy="50" r="45"/></svg>
|
|
17
|
-
<p>Computing Four Pillars…</p>
|
|
18
|
-
</div>
|
|
19
|
-
<div id="chart-status" class="chart-status" role="status" aria-live="polite"></div>
|
|
20
|
-
<div id="bazi-container" hidden></div>
|
|
21
|
-
<div id="tooltip" class="tooltip" aria-live="polite"></div>
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
<script type="module">(function() {
|
|
25
|
-
let e2 = document.createElement("link").relList;
|
|
26
|
-
if (e2 && e2.supports && e2.supports("modulepreload")) return;
|
|
27
|
-
for (let e3 of document.querySelectorAll('link[rel="modulepreload"]')) n2(e3);
|
|
28
|
-
new MutationObserver((e3) => {
|
|
29
|
-
for (let t3 of e3) if (t3.type === "childList") for (let e4 of t3.addedNodes) e4.tagName === "LINK" && e4.rel === "modulepreload" && n2(e4);
|
|
30
|
-
}).observe(document, { childList: true, subtree: true });
|
|
31
|
-
function t2(e3) {
|
|
32
|
-
let t3 = {};
|
|
33
|
-
return e3.integrity && (t3.integrity = e3.integrity), e3.referrerPolicy && (t3.referrerPolicy = e3.referrerPolicy), e3.crossOrigin === "use-credentials" ? t3.credentials = "include" : e3.crossOrigin === "anonymous" ? t3.credentials = "omit" : t3.credentials = "same-origin", t3;
|
|
34
|
-
}
|
|
35
|
-
function n2(e3) {
|
|
36
|
-
if (e3.ep) return;
|
|
37
|
-
e3.ep = true;
|
|
38
|
-
let n3 = t2(e3);
|
|
39
|
-
fetch(e3.href, n3);
|
|
40
|
-
}
|
|
41
|
-
})();
|
|
42
|
-
var e = { Jia: "\u7532", Yi: "\u4E59", Bing: "\u4E19", Ding: "\u4E01", Wu: "\u620A", Ji: "\u5DF1", Geng: "\u5E9A", Xin: "\u8F9B", Ren: "\u58EC", Gui: "\u7678" }, t = { Zi: "\u5B50", Chou: "\u4E11", Yin: "\u5BC5", Mao: "\u536F", Chen: "\u8FB0", Si: "\u5DF3", Wu: "\u5348", Wei: "\u672A", Shen: "\u7533", You: "\u9149", Xu: "\u620C", Hai: "\u4EA5" }, n = { Rat: "\u{1F400}", Ox: "\u{1F402}", Tiger: "\u{1F405}", Rabbit: "\u{1F407}", Dragon: "\u{1F409}", Snake: "\u{1F40D}", Horse: "\u{1F40E}", Goat: "\u{1F410}", Monkey: "\u{1F412}", Rooster: "\u{1F413}", Dog: "\u{1F415}", Pig: "\u{1F416}" }, r = { Wood: "var(--wuxing-wood)", Fire: "var(--wuxing-fire)", Earth: "var(--wuxing-earth)", Metal: "var(--wuxing-metal)", Water: "var(--wuxing-water)" }, i = { Wood: "var(--wuxing-wood-bg)", Fire: "var(--wuxing-fire-bg)", Earth: "var(--wuxing-earth-bg)", Metal: "var(--wuxing-metal-bg)", Water: "var(--wuxing-water-bg)" }, a = { Wood: "\u{1F333}", Fire: "\u{1F525}", Earth: "\u26F0\uFE0F", Metal: "\u2694\uFE0F", Water: "\u{1F4A7}" }, o = ["Year", "Month", "Day", "Hour"], s = ["year", "month", "day", "hour"];
|
|
43
|
-
function c(e2) {
|
|
44
|
-
let t2 = [];
|
|
45
|
-
return t2.push(l(e2)), t2.push(f(e2)), t2.push(p()), t2.join("");
|
|
46
|
-
}
|
|
47
|
-
function l(e2) {
|
|
48
|
-
return '<div class="bazi-pillars">' + s.map((t2, n2) => {
|
|
49
|
-
var r2;
|
|
50
|
-
let i2 = e2.chart[t2], a2 = (r2 = e2.ten_gods) == null || (r2 = r2.pillars) == null ? void 0 : r2[n2], s2 = n2 === 2;
|
|
51
|
-
return u(o[n2], i2, a2, s2, n2);
|
|
52
|
-
}).join("") + "</div>";
|
|
53
|
-
}
|
|
54
|
-
function u(i2, a2, o2, s2, c2) {
|
|
55
|
-
var l2, u2, f2, p2;
|
|
56
|
-
let m2 = ((l2 = a2.stem) == null ? void 0 : l2.name) || "?", g2 = ((u2 = a2.stem) == null ? void 0 : u2.element) || "", _2 = ((f2 = a2.branch) == null ? void 0 : f2.name) || "?", v2 = ((p2 = a2.branch) == null ? void 0 : p2.animal) || "", y2 = e[m2] || m2, b2 = t[_2] || _2, x2 = n[v2] || "", S2 = r[g2] || "var(--text-primary)", C2 = s2 ? " bazi-pillar--dm" : "", w2 = s2 ? '<span class="dm-badge">DM</span>' : "", T2 = "";
|
|
57
|
-
if (o2 != null && o2.visible_ten_god) {
|
|
58
|
-
let e2 = o2.visible_ten_god;
|
|
59
|
-
T2 = '<span class="bazi-ten-god-tag">' + h(e2.chinese || e2.name) + "</span>";
|
|
60
|
-
}
|
|
61
|
-
let E2 = d((o2 == null ? void 0 : o2.hidden_ten_gods) || []);
|
|
62
|
-
return '<div class="bazi-pillar' + C2 + '" data-pillar="' + c2 + '"><div class="bazi-pillar-header">' + h(i2) + " " + w2 + " " + T2 + '</div><div class="bazi-stem-zone"><span class="bazi-stem-chinese" style="color:' + S2 + '">' + h(y2) + '</span><span class="bazi-stem-name">' + h(m2) + '</span><span class="bazi-stem-element" style="background:' + S2 + '">' + h(g2) + '</span></div><div class="bazi-branch-zone"><span class="bazi-branch-animal-emoji">' + x2 + '</span><span class="bazi-branch-name">' + h(b2) + " " + h(_2) + '</span><span class="bazi-branch-animal">' + h(v2) + "</span></div>" + E2 + "</div>";
|
|
63
|
-
}
|
|
64
|
-
function d(e2) {
|
|
65
|
-
return !e2 || e2.length === 0 ? '<div class="bazi-hidden-zone"><span class="bazi-hidden-label">Hidden Stems</span><span style="font-size:10px;color:var(--text-muted)">\u2014</span></div>' : '<div class="bazi-hidden-zone"><span class="bazi-hidden-label">Hidden Stems</span><div class="bazi-hidden-stems">' + e2.map(function(e3) {
|
|
66
|
-
var t2;
|
|
67
|
-
let n2 = e3.hidden_stem, i2 = r[n2.element] || "var(--text-secondary)", a2 = "bazi-hidden-strength--" + (n2.strength || "main");
|
|
68
|
-
return '<div class="bazi-hidden-stem" title="' + h(n2.name) + " (" + h(n2.element) + " " + h(n2.polarity) + ") \u2014 " + h(((t2 = e3.ten_god) == null ? void 0 : t2.name) || "") + '"><span class="bazi-hidden-char" style="color:' + i2 + '">' + h(n2.chinese || n2.name) + '</span><span class="bazi-hidden-strength ' + a2 + '" style="background:' + i2 + '"></span></div>';
|
|
69
|
-
}).join("") + "</div></div>";
|
|
70
|
-
}
|
|
71
|
-
function f(e2) {
|
|
72
|
-
let t2 = e2.element_balance;
|
|
73
|
-
if (!t2 || !t2.elements || t2.elements.length === 0) return "";
|
|
74
|
-
let n2 = ["Wood", "Fire", "Earth", "Metal", "Water"].map(function(e3) {
|
|
75
|
-
return t2.elements.find(function(t3) {
|
|
76
|
-
return t3.element === e3;
|
|
77
|
-
});
|
|
78
|
-
}).filter(Boolean), o2 = t2.day_master_strength || "neutral", s2 = o2 === "strong" ? "bazi-balance-strength--strong" : o2 === "weak" ? "bazi-balance-strength--weak" : "", c2 = o2.charAt(0).toUpperCase() + o2.slice(1), l2 = n2.map(function(e3) {
|
|
79
|
-
let t3 = Math.max(e3.percentage, 3), n3 = r[e3.element] || "var(--text-primary)", a2 = i[e3.element] || "var(--bg-tertiary)", o3 = e3.percentage >= 12 ? '<span class="bazi-bar-segment-label">' + Math.round(e3.percentage) + "%</span>" : "";
|
|
80
|
-
return '<div class="bazi-bar-segment" style="flex:' + t3 + ";background:" + a2 + ";color:" + n3 + '">' + o3 + "</div>";
|
|
81
|
-
}).join(""), u2 = n2.map(function(e3) {
|
|
82
|
-
let t3 = r[e3.element] || "var(--text-primary)", n3 = a[e3.element] || "";
|
|
83
|
-
return '<div class="bazi-legend-item"><span class="bazi-legend-dot" style="background:' + t3 + '"></span><span>' + n3 + " " + h(e3.element) + '</span><span class="bazi-legend-pct">' + Math.round(e3.percentage) + '%</span><span class="bazi-legend-score">(' + e3.score.toFixed(1) + ")</span></div>";
|
|
84
|
-
}).join(""), d2 = t2.yong_shen_element || "", f2 = a[d2] || "", p2 = d2 ? '<div class="bazi-yongshen"><span class="bazi-yongshen-label">Useful God (\u7528\u795E)</span><span class="bazi-yongshen-value" style="color:' + (r[d2] || "inherit") + '">' + f2 + " " + h(d2) + "</span></div>" : "";
|
|
85
|
-
return '<div class="bazi-balance"><div class="bazi-balance-header"><span class="bazi-balance-title">Wu Xing Balance</span><span class="bazi-balance-strength ' + s2 + '">' + h(t2.day_master_element || "") + " Day Master \u2014 " + h(c2) + '</span></div><div class="bazi-bar-container">' + l2 + '</div><div class="bazi-bar-legend">' + u2 + "</div>" + p2 + "</div>";
|
|
86
|
-
}
|
|
87
|
-
function p() {
|
|
88
|
-
return '<div class="bazi-actions"><button class="action-btn action-btn--primary" data-action="ask-claude" data-query="day-master">\u{1F52E} Interpret My Day Master</button><button class="action-btn" data-action="ask-claude" data-query="element-balance">\u2696\uFE0F Analyse My Element Balance</button><button class="action-btn" data-action="ask-claude" data-query="ten-gods">\u{1F3DB}\uFE0F Explain My Ten Gods</button></div>';
|
|
89
|
-
}
|
|
90
|
-
function m(i2, a2) {
|
|
91
|
-
var c2, l2, u2, d2, f2;
|
|
92
|
-
let p2 = o[a2] || "Pillar", m2 = i2.chart[s[a2]], g2 = (c2 = i2.ten_gods) == null || (c2 = c2.pillars) == null ? void 0 : c2[a2], _2 = ((l2 = m2.stem) == null ? void 0 : l2.name) || "?", v2 = ((u2 = m2.stem) == null ? void 0 : u2.element) || "", y2 = ((d2 = m2.branch) == null ? void 0 : d2.name) || "?", b2 = ((f2 = m2.branch) == null ? void 0 : f2.animal) || "", x2 = e[_2] || _2, S2 = t[y2] || y2, C2 = r[v2] || "var(--text-primary)", w2 = "";
|
|
93
|
-
if (g2 != null && g2.visible_ten_god) {
|
|
94
|
-
let e2 = g2.visible_ten_god;
|
|
95
|
-
w2 = '<div class="bazi-drawer-section"><div class="bazi-drawer-section-title">Ten God (\u5341\u795E)</div><div class="bazi-drawer-ten-god"><span class="bazi-drawer-tg-chinese" style="color:' + C2 + '">' + h(e2.chinese || "") + '</span><div class="bazi-drawer-tg-info"><span class="bazi-drawer-tg-name">' + h(e2.name) + " (" + h(e2.pinyin || "") + ')</span><span class="bazi-drawer-tg-category">' + h(e2.category) + "</span></div></div></div>";
|
|
96
|
-
} else a2 === 2 && (w2 = '<div class="bazi-drawer-section"><div class="bazi-drawer-section-title">Day Master (\u65E5\u4E3B)</div><p style="font-size:12px;color:var(--text-secondary)">This is your Day Master \u2014 the stem that represents you. Ten Gods are calculated relative to this pillar.</p></div>');
|
|
97
|
-
let T2 = (g2 == null ? void 0 : g2.hidden_ten_gods) || [], E2 = "";
|
|
98
|
-
return T2.length > 0 && (E2 = '<div class="bazi-drawer-section"><div class="bazi-drawer-section-title">Hidden Stems (\u85CF\u5E72)</div><table class="bazi-drawer-hidden-table"><thead><tr><th>Stem</th><th>Element</th><th>Strength</th><th>Ten God</th></tr></thead><tbody>' + T2.map(function(e2) {
|
|
99
|
-
let t2 = e2.hidden_stem, n2 = e2.ten_god;
|
|
100
|
-
return '<tr><td style="color:' + (r[t2.element] || "inherit") + ';font-weight:700">' + h(t2.chinese || t2.name) + " " + h(t2.name) + "</td><td>" + h(t2.element) + " " + h(t2.polarity) + "</td><td>" + h(t2.strength) + " (" + t2.weight.toFixed(1) + ")</td><td>" + h((n2 == null ? void 0 : n2.name) || "\u2014") + " " + h((n2 == null ? void 0 : n2.chinese) || "") + "</td></tr>";
|
|
101
|
-
}).join("") + "</tbody></table></div>"), '<div class="bazi-drawer-handle"></div><div class="bazi-drawer-title"><span style="color:' + C2 + '">' + h(x2) + h(S2) + "</span> " + h(p2) + " Pillar \u2014 " + h(_2) + " " + h(y2) + " (" + (n[b2] || "") + " " + h(b2) + ")</div>" + w2 + E2 + '<div class="bazi-drawer-section"><button class="action-btn action-btn--primary" data-action="ask-claude" data-query="pillar-' + a2 + '">\u{1F52E} Interpret this ' + h(p2) + " Pillar</button></div>";
|
|
102
|
-
}
|
|
103
|
-
function h(e2) {
|
|
104
|
-
return e2 ? e2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """) : "";
|
|
105
|
-
}
|
|
106
|
-
var g = null, _ = false, v = document.getElementById("loading-state"), y = document.getElementById("bazi-container"), b = document.getElementById("chart-status"), x = document.getElementById("tooltip");
|
|
107
|
-
function S() {
|
|
108
|
-
let e2 = window.__BAZI_DATA__;
|
|
109
|
-
if (!e2 || !e2.chart) {
|
|
110
|
-
A("No BaZi data was provided.");
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
g = e2, y.innerHTML = c(e2), v.hidden = true, y.hidden = false;
|
|
114
|
-
let t2 = e2.chart.day_master;
|
|
115
|
-
t2 && k("Day Master: " + (t2.stem || "\u2014") + " " + (t2.element || "\u2014")), C(), document.addEventListener("keydown", function(e3) {
|
|
116
|
-
if (e3.key === "Escape" && _) {
|
|
117
|
-
let e4 = document.querySelector(".bazi-drawer-overlay"), t3 = document.querySelector(".bazi-drawer");
|
|
118
|
-
e4 && t3 && E(e4, t3);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
function C() {
|
|
123
|
-
y.addEventListener("click", function(e2) {
|
|
124
|
-
let t2 = e2.target, n2 = t2.closest("[data-action]");
|
|
125
|
-
if (n2) {
|
|
126
|
-
D(n2);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
let r2 = t2.closest("[data-pillar]");
|
|
130
|
-
r2 && g && T(parseInt(r2.getAttribute("data-pillar") || "0", 10));
|
|
131
|
-
}), y.addEventListener("mouseover", function(e2) {
|
|
132
|
-
let t2 = e2.target.closest(".bazi-hidden-stem");
|
|
133
|
-
if (t2) {
|
|
134
|
-
let n2 = t2.getAttribute("title");
|
|
135
|
-
n2 && (x.textContent = n2, x.classList.add("visible"), w(e2));
|
|
136
|
-
}
|
|
137
|
-
}), y.addEventListener("mouseout", function(e2) {
|
|
138
|
-
e2.target.closest(".bazi-hidden-stem") && x.classList.remove("visible");
|
|
139
|
-
}), y.addEventListener("mousemove", function(e2) {
|
|
140
|
-
x.classList.contains("visible") && w(e2);
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
function w(e2) {
|
|
144
|
-
x.style.left = e2.clientX + 12 + "px", x.style.top = e2.clientY - 30 + "px";
|
|
145
|
-
}
|
|
146
|
-
function T(e2) {
|
|
147
|
-
if (!g || _) return;
|
|
148
|
-
_ = true;
|
|
149
|
-
let t2 = document.createElement("div");
|
|
150
|
-
t2.className = "bazi-drawer-overlay";
|
|
151
|
-
let n2 = document.createElement("div");
|
|
152
|
-
n2.className = "bazi-drawer", n2.innerHTML = m(g, e2), n2.addEventListener("click", function(e3) {
|
|
153
|
-
let r2 = e3.target.closest("[data-action]");
|
|
154
|
-
r2 && (D(r2), E(t2, n2));
|
|
155
|
-
}), document.body.appendChild(t2), document.body.appendChild(n2), requestAnimationFrame(function() {
|
|
156
|
-
t2.classList.add("visible"), n2.classList.add("visible");
|
|
157
|
-
}), t2.addEventListener("click", function() {
|
|
158
|
-
E(t2, n2);
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
function E(e2, t2) {
|
|
162
|
-
e2.classList.remove("visible"), t2.classList.remove("visible"), setTimeout(function() {
|
|
163
|
-
e2.remove(), t2.remove(), _ = false;
|
|
164
|
-
}, 250);
|
|
165
|
-
}
|
|
166
|
-
function D(e2) {
|
|
167
|
-
let t2 = e2.getAttribute("data-action"), n2 = e2.getAttribute("data-query") || "";
|
|
168
|
-
if (t2 === "ask-claude" && g) {
|
|
169
|
-
var r2;
|
|
170
|
-
let e3 = O(n2, g);
|
|
171
|
-
(r2 = window.__mcp_host__) != null && r2.askClaude && window.__mcp_host__.askClaude(e3);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
function O(e2, t2) {
|
|
175
|
-
let n2 = t2.chart.day_master, r2 = ((n2 == null ? void 0 : n2.stem) || "") + " " + ((n2 == null ? void 0 : n2.element) || "");
|
|
176
|
-
if (e2 === "day-master") {
|
|
177
|
-
var i2, a2;
|
|
178
|
-
return "Interpret my BaZi Day Master: " + r2 + ". My element balance shows " + (((i2 = t2.element_balance) == null ? void 0 : i2.day_master_strength) || "unknown") + " strength. Useful God (Yong Shen): " + (((a2 = t2.element_balance) == null ? void 0 : a2.yong_shen_element) || "unknown") + ". Give me personality traits, strengths, challenges, and practical advice.";
|
|
179
|
-
}
|
|
180
|
-
if (e2 === "element-balance") {
|
|
181
|
-
var o2, s2, c2;
|
|
182
|
-
return "Analyse my BaZi Wu Xing element balance: " + (((o2 = t2.element_balance) == null ? void 0 : o2.elements) || []).map(function(e3) {
|
|
183
|
-
return e3.element + " " + Math.round(e3.percentage) + "%";
|
|
184
|
-
}).join(", ") + ". Day Master strength: " + (((s2 = t2.element_balance) == null ? void 0 : s2.day_master_strength) || "unknown") + ". Yong Shen: " + (((c2 = t2.element_balance) == null ? void 0 : c2.yong_shen_element) || "unknown") + ". Explain what this balance means for my health, career, and relationships.";
|
|
185
|
-
}
|
|
186
|
-
if (e2 === "ten-gods") {
|
|
187
|
-
var l2;
|
|
188
|
-
return "Explain my BaZi Ten Gods configuration: " + (((l2 = t2.ten_gods) == null ? void 0 : l2.pillars) || []).filter(function(e3) {
|
|
189
|
-
return e3.visible_ten_god;
|
|
190
|
-
}).map(function(e3) {
|
|
191
|
-
var t3;
|
|
192
|
-
return e3.pillar + ": " + (((t3 = e3.visible_ten_god) == null ? void 0 : t3.name) || "");
|
|
193
|
-
}).join(", ") + ". Day Master: " + r2 + ". How do these Ten Gods shape my destiny and what areas of life do they govern?";
|
|
194
|
-
}
|
|
195
|
-
if (e2.startsWith("pillar-")) {
|
|
196
|
-
var u2, d2, f2;
|
|
197
|
-
let n3 = parseInt(e2.replace("pillar-", ""), 10), i3 = ["Year", "Month", "Day", "Hour"], a3 = ["year", "month", "day", "hour"], o3 = i3[n3] || "Unknown", s3 = t2.chart[a3[n3]], c3 = (s3 == null || (u2 = s3.stem) == null ? void 0 : u2.name) || "?", l3 = (s3 == null || (d2 = s3.branch) == null ? void 0 : d2.name) || "?", p2 = (s3 == null || (f2 = s3.branch) == null ? void 0 : f2.animal) || "?";
|
|
198
|
-
return "Interpret my BaZi " + o3 + " Pillar in depth: " + c3 + " " + l3 + " (" + p2 + "). Day Master: " + r2 + ". What does this pillar reveal about my " + (n3 === 0 ? "ancestry, early influences, and social facade" : n3 === 1 ? "career, parents, and middle years" : n3 === 2 ? "core self, spouse, and inner character" : "children, ambitions, and later years") + "?";
|
|
199
|
-
}
|
|
200
|
-
return "Interpret my BaZi Four Pillars chart. Day Master: " + r2;
|
|
201
|
-
}
|
|
202
|
-
function k(e2) {
|
|
203
|
-
b.textContent = e2, b.classList.add("visible"), setTimeout(function() {
|
|
204
|
-
b.classList.remove("visible");
|
|
205
|
-
}, 4e3);
|
|
206
|
-
}
|
|
207
|
-
function A(e2) {
|
|
208
|
-
v.hidden = true, y.hidden = false, y.innerHTML = '<div class="error-state"><span class="error-icon">\u26A0\uFE0F</span><p>' + e2 + "</p></div>";
|
|
209
|
-
}
|
|
210
|
-
document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", S) : S();
|
|
211
|
-
</script>
|
|
212
|
-
</body>
|
|
213
|
-
</html>
|