@openephemeris/mcp-server 3.16.0 → 3.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/LICENSE +21 -21
- package/README.md +6 -4
- package/dist/backend/client.d.ts +9 -0
- package/dist/backend/client.js +35 -6
- 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/oauth/token.js +54 -7
- package/dist/server-sse.js +184 -20
- package/dist/tools/apps/bodygraph-app.d.ts +2 -1
- package/dist/tools/apps/bodygraph-app.js +144 -1
- 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/chart-wheel.html +15 -20
- package/dist/ui/moon-phase.html +28 -28
- package/package.json +4 -2
- 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
package/dist/ui/chart-wheel.html
CHANGED
|
@@ -7535,32 +7535,29 @@ function Zv(e4) {
|
|
|
7535
7535
|
n2(e5);
|
|
7536
7536
|
});
|
|
7537
7537
|
}
|
|
7538
|
-
var Qv = document.getElementById("loading-state"), $v = document.getElementById("chart-container"), ey = document.getElementById("chart-info"), ty = document.getElementById("chart-status"), ny = document.getElementById("controls-panel"), ry = document.getElementById("patterns-strip"), iy = document.getElementById("aspect-filter"), ay = document.getElementById("overview-table"), oy = document.getElementById("param-controls-container");
|
|
7539
|
-
console.log("[ChartWheel] \u{1F680} main.ts loaded, creating App instance...");
|
|
7540
|
-
var sy = new r_({ name: "Chart Wheel Explorer", version: "1.0.0" }), $ = null, cy = "placidus", ly = null, uy = false, dy = false;
|
|
7538
|
+
var Qv = document.getElementById("loading-state"), $v = document.getElementById("chart-container"), ey = document.getElementById("chart-info"), ty = document.getElementById("chart-status"), ny = document.getElementById("controls-panel"), ry = document.getElementById("patterns-strip"), iy = document.getElementById("aspect-filter"), ay = document.getElementById("overview-table"), oy = document.getElementById("param-controls-container"), sy = new r_({ name: "Chart Wheel Explorer", version: "1.0.0" }), $ = null, cy = "placidus", ly = null, uy = false, dy = false;
|
|
7541
7539
|
function fy(e4) {
|
|
7542
7540
|
ty && (e4 ? (ty.textContent = "\xB7 ".concat(e4), ty.setAttribute("data-active", "")) : (ty.textContent = "", ty.removeAttribute("data-active")));
|
|
7543
7541
|
}
|
|
7544
7542
|
sy.ontoolresult = (e4) => {
|
|
7545
|
-
var t2
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
if (Fy(), !o2 || !o2.planets) {
|
|
7543
|
+
var t2;
|
|
7544
|
+
let n2 = Gv(e4);
|
|
7545
|
+
if (Fy(), !n2 || !n2.planets) {
|
|
7549
7546
|
console.error("[ChartWheel] \u274C No chart data found in tool result"), Iy("Chart data could not be parsed from the server response.", Ly);
|
|
7550
7547
|
return;
|
|
7551
7548
|
}
|
|
7552
|
-
if ($ =
|
|
7553
|
-
var
|
|
7554
|
-
let e5 = (
|
|
7549
|
+
if ($ = n2, cy = (t2 = n2.house_system) == null ? "placidus" : t2, !ly) {
|
|
7550
|
+
var r2, i2, a2, o2, s2, c2, l2, u2, d2, f2;
|
|
7551
|
+
let e5 = (r2 = n2._birth_params) == null ? {} : r2, t3 = (i2 = (a2 = (o2 = e5.datetime) == null ? n2.datetime : o2) == null ? n2.birth_datetime : a2) == null ? "" : i2, p2 = (s2 = (c2 = e5.location) == null ? n2.location : c2) == null ? "" : s2, m2 = (l2 = (u2 = e5.timezone) == null ? n2.timezone : u2) == null ? "" : l2, h2 = (d2 = e5.latitude) == null ? n2.latitude : d2, g2 = (f2 = e5.longitude) == null ? n2.longitude : f2, _2 = "", v2 = "12:00";
|
|
7555
7552
|
if (t3 && t3.includes("T")) {
|
|
7556
7553
|
let e6 = t3.split("T");
|
|
7557
7554
|
_2 = e6[0], v2 = e6[1].substring(0, 5);
|
|
7558
7555
|
}
|
|
7559
|
-
ly = new Iv({ app: sy, container: oy, initialParams: { date: _2, time: v2, locationName:
|
|
7556
|
+
ly = new Iv({ app: sy, container: oy, initialParams: { date: _2, time: v2, locationName: p2, timezone: m2, latitude: typeof h2 == "number" ? h2 : null, longitude: typeof g2 == "number" ? g2 : null }, showStepControls: false, onRefresh: async (e6) => {
|
|
7560
7557
|
ly == null || ly.setBusy(true), Qv.removeAttribute("hidden"), $v.setAttribute("hidden", "");
|
|
7561
7558
|
try {
|
|
7562
|
-
var t4,
|
|
7563
|
-
let
|
|
7559
|
+
var t4, n3, r3, i3;
|
|
7560
|
+
let a3 = "".concat(e6.date, "T").concat(e6.time, ":00"), o3 = new Promise((e7, t5) => setTimeout(() => t5(Error("Recalculate timed out after 30s")), 3e4)), s3 = Gv(await Promise.race([sy.callServerTool({ name: "chart_wheel_recalculate", arguments: { datetime: "".concat(a3).concat(e6.timezone ? "" : "Z"), latitude: (t4 = e6.latitude) == null ? void 0 : t4, longitude: (n3 = e6.longitude) == null ? void 0 : n3, timezone: (r3 = e6.timezone) == null ? void 0 : r3, location: (i3 = e6.locationName) == null ? void 0 : i3, house_system: cy || "placidus", chart_type: "natal" } }), o3]));
|
|
7564
7561
|
s3 ? ($ = s3, s3.house_system && (cy = s3.house_system), py(s3)) : $ && (Qv.setAttribute("hidden", ""), $v.removeAttribute("hidden"));
|
|
7565
7562
|
} catch (e7) {
|
|
7566
7563
|
console.error("[ChartWheel] Recalculate failed or timed out:", e7), $ && (Qv.setAttribute("hidden", ""), $v.removeAttribute("hidden"));
|
|
@@ -7569,7 +7566,7 @@ sy.ontoolresult = (e4) => {
|
|
|
7569
7566
|
}
|
|
7570
7567
|
} });
|
|
7571
7568
|
}
|
|
7572
|
-
|
|
7569
|
+
py(n2);
|
|
7573
7570
|
};
|
|
7574
7571
|
function py(e4) {
|
|
7575
7572
|
var t2, n2, r2, i2, a2, o2, s2;
|
|
@@ -7749,7 +7746,7 @@ function Cy() {
|
|
|
7749
7746
|
async function wy(e4, t2) {
|
|
7750
7747
|
if (uy) try {
|
|
7751
7748
|
let n2 = "[Chart Wheel] Selected ".concat(e4, " \u2014 ").concat(Object.entries(t2).filter(([, e5]) => e5 != null && e5 !== false && e5 !== "").map(([e5, t3]) => "".concat(e5, ": ").concat(t3)).join(", "));
|
|
7752
|
-
await sy.updateModelContext({ content: [{ type: "text", text: n2 }] })
|
|
7749
|
+
await sy.updateModelContext({ content: [{ type: "text", text: n2 }] });
|
|
7753
7750
|
} catch (e5) {
|
|
7754
7751
|
console.warn("[ChartWheel] \u26A0\uFE0F updateModelContext failed:", e5);
|
|
7755
7752
|
}
|
|
@@ -7842,10 +7839,8 @@ async function My(e4) {
|
|
|
7842
7839
|
t2 = "Interpret the ".concat(n3.angle, " at ").concat(n3.position, " (").concat(n3.sign, " \xB7 ").concat(n3.element, " \xB7 ").concat(n3.modality, ") in this natal chart. Give a focused interpretation of what this angle represents for the native \u2014 identity, life direction, relationships, or roots depending on which angle \u2014 and how the sign on the angle shapes that expression.");
|
|
7843
7840
|
}
|
|
7844
7841
|
if (t2) try {
|
|
7845
|
-
console.log("[ChartWheel] \u{1F4AC} Sending interpretation request to Claude...");
|
|
7846
7842
|
let e5 = await sy.sendMessage({ role: "user", content: [{ type: "text", text: t2 }] });
|
|
7847
7843
|
if (e5.isError) throw console.error("[ChartWheel] \u274C Host rejected sendMessage:", e5), Error("Host rejected message");
|
|
7848
|
-
console.log("[ChartWheel] \u2705 Message sent to chat thread");
|
|
7849
7844
|
} catch (e5) {
|
|
7850
7845
|
throw console.error("[ChartWheel] \u274C sendMessage failed:", e5), e5;
|
|
7851
7846
|
}
|
|
@@ -7878,11 +7873,11 @@ function Ly() {
|
|
|
7878
7873
|
}
|
|
7879
7874
|
Yv(sy, { loadingEl: Qv, contentEl: $v, statusFn: fy, paramControls: ly }), Py = setTimeout(() => {
|
|
7880
7875
|
Iy("Chart data is taking longer than expected.", Ly);
|
|
7881
|
-
}, 3e4),
|
|
7876
|
+
}, 3e4), (async () => {
|
|
7882
7877
|
try {
|
|
7883
|
-
await sy.connect()
|
|
7878
|
+
await sy.connect();
|
|
7884
7879
|
let e4 = sy.getHostCapabilities();
|
|
7885
|
-
uy = !!(e4 != null && e4.modelContext), dy = !!(e4 != null && e4.sampling),
|
|
7880
|
+
uy = !!(e4 != null && e4.modelContext), dy = !!(e4 != null && e4.sampling), Jv(sy, document.getElementById("pan-zoom-controls"), ["aspect-filter", "controls-panel", "param-controls-container", "chart-info", "patterns-strip", "info-panel", "cw-action-bar"]), Zv(sy), $ && py($);
|
|
7886
7881
|
} catch (e4) {
|
|
7887
7882
|
console.error("[ChartWheel] \u274C app.connect() FAILED:", e4), Iy("Connection failed: ".concat(e4 instanceof Error ? e4.message : String(e4)));
|
|
7888
7883
|
}
|
package/dist/ui/moon-phase.html
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
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
|
-
<meta name="mcp-app-preferred-height" content="560" />
|
|
8
|
-
<title>Moon Phase Explorer</title>
|
|
9
|
-
<!-- External Google Fonts removed: Claude.ai sandbox enforces hardcoded
|
|
10
|
-
frame-src 'self' blob: data: and blocks external CDN fetches at
|
|
11
|
-
iframe render time. Styles fall back to the system font stack. -->
|
|
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
|
+
<meta name="mcp-app-preferred-height" content="560" />
|
|
8
|
+
<title>Moon Phase Explorer</title>
|
|
9
|
+
<!-- External Google Fonts removed: Claude.ai sandbox enforces hardcoded
|
|
10
|
+
frame-src 'self' blob: data: and blocks external CDN fetches at
|
|
11
|
+
iframe render time. Styles fall back to the system font stack. -->
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
<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;--voc-warn:#f6922e;--cue-warm:#f4a34b;--cue-cool:#6ab3fd;--radius:8px;--radius-sm:4px;--radius-lg:12px;--font-display:"Space Grotesk", system-ui, sans-serif;--font-body:"Inter", system-ui, sans-serif;--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);--voc-warn:color(display-p3 .910067 .591092 .274641);--cue-warm:color(display-p3 .911412 .653072 .360243);--cue-cool:color(display-p3 .48245 .695507 .967802)}}@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);--voc-warn:lab(70.3313% 33.71 65.3029);--cue-warm:lab(74.0849% 25.4197 56.7058);--cue-cool:lab(70.5454% -7.4636 -44.2057)}}@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:#585e67;--accent:#0065b2;--accent-warm:#966800;--voc-warn:#a95a00;--cue-warm:#954200;--cue-cool:#1e5ba1;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}@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 .350602 .367691 .400197);--accent:color(display-p3 .143802 .388951 .683672);--accent-warm:color(display-p3 .596632 .396992 -.158844);--voc-warn:color(display-p3 .673365 .329149 -.157701);--cue-warm:color(display-p3 .567457 .255699 -.0353967);--cue-cool:color(display-p3 .186321 .349931 .613332)}}@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(39.6225% -.718519 -5.91861);--accent:lab(41.1205% -1.70796 -50.1423);--accent-warm:lab(47.6194% 20.1868 104.51);--voc-warn:lab(46.8395% 41.0975 106.287);--cue-warm:lab(38.6598% 39.325 67.0649);--cue-cool:lab(37.6228% 1.24846 -44.7496)}}}html,body{width:100%;height:100%;min-height:480px;font-family:var(--font-body);background:var(--bg-primary);color:var(--text-primary);font-size:13px;line-height:1.5;overflow-y:auto}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)}.pan-zoom-controls{z-index:40;gap:4px;display:flex;position:fixed;top:8px;right:8px}.pan-zoom-controls[hidden]{display:none}.pan-btn{background:var(--bg-tertiary);border:1px solid var(--border);border-radius:var(--radius-sm);width:28px;height:28px;color:var(--text-secondary);cursor:pointer;justify-content:center;align-items:center;font-size:14px;transition:background .15s,color .15s;display:flex}.pan-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.pan-btn.reset{width:auto;padding:0 10px;font-size:12px}#moon-container{flex-direction:column;flex:1;min-height:440px;padding:16px;display:flex;overflow-y:auto}#moon-container[hidden]{display:none}.moon-layout{flex:1;align-items:flex-start;gap:24px;display:flex}@media (max-width:500px){.moon-layout{flex-direction:column;align-items:center;gap:16px}}.moon-dial-col{flex-direction:column;flex-shrink:0;align-items:center;gap:12px;display:flex}.moon-dial{justify-content:center;align-items:center;width:200px;height:200px;display:flex;position:relative}.moon-svg{filter:drop-shadow(0 0 20px rgba(131,163,187,.2));filter:drop-shadow(0 0 20px color(display-p3 .537913 .6362 .723376/.2));filter:drop-shadow(0 0 20px lab(65.2381% -7.35197 -16.1178/.2));width:100%;height:100%;animation:.8s ease-out moon-fade-in}@keyframes moon-fade-in{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}.moon-illum-ring{background:var(--bg-secondary);border:1px solid var(--border-subtle);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-radius:20px;flex-direction:column;align-items:center;gap:1px;padding:3px 10px;display:flex;position:absolute;bottom:-2px}.moon-illum-value{font-size:22px;font-weight:700;font-family:var(--font-display);font-variant-numeric:tabular-nums;color:var(--accent-warm);letter-spacing:-.02em}.moon-illum-label{text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);font-size:9px}.moon-phase-badge{background:var(--bg-secondary);border:1px solid var(--border);border-radius:20px;align-items:center;gap:6px;padding:6px 14px;display:flex}.moon-phase-icon{font-size:18px}.moon-phase-name{font-size:15px;font-weight:700;font-family:var(--font-display);letter-spacing:-.01em;text-transform:capitalize}.moon-direction{color:var(--text-muted);align-items:center;gap:4px;font-size:12px;display:flex}.dir-arrow{font-size:14px;font-weight:700}.dir-waxing{color:#57bc8a;color:color(display-p3 .44464 .726476 .557142);color:lab(69.1118% -39.6203 15.6094)}.dir-waning{color:#e6857e;color:color(display-p3 .850722 .541293 .507352);color:lab(66.3643% 37.397 20.9063)}.moon-info-col{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.moon-card{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius);cursor:pointer;padding:10px 14px;transition:background .15s,border-color .15s,box-shadow .15s}.moon-card:hover{background:var(--bg-hover);border-color:var(--border);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)}.moon-card--voc.moon-card--active{border-color:var(--voc-warn);background:#2c1e13;background:color(display-p3 .165435 .120647 .0798046);background:lab(12.9057% 5.79391 10.6146)}@media (prefers-color-scheme:light){.moon-card--voc.moon-card--active{background:#ffead8;background:color(display-p3 1.00032 .917094 .842425);background:lab(94.1113% 7.0433 13.5336)}}.moon-card-header{align-items:center;gap:6px;margin-bottom:4px;display:flex}.moon-card-icon{font-size:14px}.moon-card-title{font-size:11px;font-weight:600;font-family:var(--font-body);text-transform:uppercase;letter-spacing:.07em;color:var(--text-muted)}.moon-card-chevron{color:var(--text-muted);flex-shrink:0;margin-left:auto;font-size:13px;transition:transform .2s}.moon-card--open .moon-card-chevron{transform:rotate(90deg)}.moon-card-value{font-size:16px;font-weight:700;font-family:var(--font-display);color:var(--text-primary);text-transform:capitalize;line-height:1.2}.moon-card-detail{color:var(--text-muted);margin-top:2px;font-size:11px}.moon-card--primary{border-color:var(--border);padding:8px 13px}.moon-card--primary .moon-card-value{letter-spacing:-.02em;font-size:16px}.moon-card--primary .moon-card-header{margin-bottom:2px}.moon-card--primary .moon-card-title{font-size:10px}.moon-card--compact{padding:6px 12px}.moon-card--compact .moon-card-header{margin-bottom:2px}.moon-card--compact .moon-card-value{font-size:13px;font-weight:600}.moon-card--compact .moon-card-title{letter-spacing:.06em;font-size:10px}.moon-card--inline{padding:6px 12px}.moon-card--inline .moon-card-header{gap:8px;margin-bottom:0}.moon-card--inline .moon-card-title{letter-spacing:.06em;font-size:10px}.moon-card-inline-value{font-family:var(--font-display);color:var(--text-primary);font-variant-numeric:tabular-nums;letter-spacing:-.01em;margin-left:auto;font-size:13px;font-weight:600}.moon-card-inline-value.tempo-fast,.moon-card-inline-value.prox-super{color:var(--cue-warm)}.moon-card-inline-value.tempo-slow{color:var(--cue-cool)}.moon-card-inline-value.prox-micro{color:var(--text-secondary)}.moon-card--inline .moon-card-chevron{margin-left:0}.moon-card-expand{grid-template-rows:0fr;margin-top:0;transition:grid-template-rows .22s,margin-top .22s;display:grid}.moon-card--open .moon-card-expand{grid-template-rows:1fr;margin-top:8px}.moon-card-expand-inner{overflow:hidden}.moon-card-expand-text{font-size:11px;font-family:var(--font-body);color:var(--text-secondary);border-top:1px solid var(--border-subtle);padding-top:7px;font-style:italic;line-height:1.55;display:block}.moon-card-row{color:var(--text-secondary);align-items:center;gap:4px;padding:1px 0;font-size:12px;display:flex}.moon-card-row-icon{font-size:12px}.moon-actions{flex-wrap:wrap;gap:8px;margin-top:6px;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:#11397b;background:color(display-p3 .112797 .221529 .46413);background:lab(24.6079% 7.13965 -41.9262);border-color:#305289;border-color:color(display-p3 .218625 .316452 .521702);border-color:lab(34.3143% 2.02942 -35.2838)}.action-btn--primary:hover{background:#1b478f;background:color(display-p3 .151166 .273205 .543079);background:lab(30.361% 6.93905 -45.4659);box-shadow:0 0 0 1px #3862a7;box-shadow:0 0 0 1px color(display-p3 .2584 .379139 .634372);box-shadow:0 0 0 1px lab(41.0971% 2.98774 -42.2721)}.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}.error-retry-btn{border:1px solid var(--border,rgba(128,128,160,.3));color:var(--accent-warm,var(--text-primary,inherit));font:inherit;letter-spacing:.02em;cursor:pointer;background:0 0;border-radius:999px;margin-top:4px;padding:7px 20px;font-size:11px;font-weight:600;transition:background .18s,border-color .18s}.error-retry-btn:hover{background:rgba(128,128,160,.12)}.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}.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%}}
|
|
15
15
|
/*$vite$:1*/</style>
|
|
16
|
-
</head>
|
|
17
|
-
<body>
|
|
18
|
-
<div id="app">
|
|
19
|
-
<div id="loading-state">
|
|
20
|
-
<svg class="oe-loader" viewBox="0 0 100 100"><circle cx="50" cy="50" r="45"/></svg>
|
|
21
|
-
<p>Computing lunar phase…</p>
|
|
22
|
-
</div>
|
|
23
|
-
<div id="chart-status" class="chart-status" aria-live="polite"></div>
|
|
24
|
-
<!-- Moon phase doesn't need zoom — image is fixed. Container is kept so
|
|
25
|
-
setupFullscreenToggle has a host to inject the fullscreen button into. -->
|
|
26
|
-
<div id="pan-zoom-controls" class="pan-zoom-controls" hidden></div>
|
|
27
|
-
<div id="moon-container" hidden></div>
|
|
28
|
-
<div id="tooltip" class="tooltip" aria-live="polite"></div>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<div id="app">
|
|
19
|
+
<div id="loading-state">
|
|
20
|
+
<svg class="oe-loader" viewBox="0 0 100 100"><circle cx="50" cy="50" r="45"/></svg>
|
|
21
|
+
<p>Computing lunar phase…</p>
|
|
22
|
+
</div>
|
|
23
|
+
<div id="chart-status" class="chart-status" aria-live="polite"></div>
|
|
24
|
+
<!-- Moon phase doesn't need zoom — image is fixed. Container is kept so
|
|
25
|
+
setupFullscreenToggle has a host to inject the fullscreen button into. -->
|
|
26
|
+
<div id="pan-zoom-controls" class="pan-zoom-controls" hidden></div>
|
|
27
|
+
<div id="moon-container" hidden></div>
|
|
28
|
+
<div id="tooltip" class="tooltip" aria-live="polite"></div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
31
|
<script type="module">var e = Object.defineProperty, t = (t2, n2) => {
|
|
32
32
|
let r2 = {};
|
|
33
33
|
for (var i2 in t2) e(r2, i2, { get: t2[i2], enumerable: true });
|
|
@@ -6783,5 +6783,5 @@ y_.ontoolresult = function(e4) {
|
|
|
6783
6783
|
}
|
|
6784
6784
|
})();
|
|
6785
6785
|
</script>
|
|
6786
|
-
</body>
|
|
6787
|
-
</html>
|
|
6786
|
+
</body>
|
|
6787
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openephemeris/mcp-server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.0",
|
|
4
4
|
"description": "Model Context Protocol server for the Open Ephemeris astronomical computation API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test": "test"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build:ui": "cd src/ui/chart-wheel && npx vite build && cd ../../.. && cd src/ui/bodygraph && npx vite build && cd ../../.. && cd src/ui/bi-wheel && npx vite build && cd ../../.. && cd src/ui/
|
|
23
|
+
"build:ui": "cd src/ui/chart-wheel && npx vite build && cd ../../.. && cd src/ui/bodygraph && npx vite build && cd ../../.. && cd src/ui/bi-wheel && npx vite build && cd ../../.. && cd src/ui/moon-phase && npx vite build",
|
|
24
24
|
"build": "npm run build:ui && tsc -p tsconfig.build.json",
|
|
25
25
|
"prebuild": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
26
26
|
"dev": "tsx watch src/index.ts",
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
"validate:visual": "node scripts/visual-check.mjs",
|
|
34
34
|
"test:integration": "tsx scripts/test-client.ts",
|
|
35
35
|
"test:sse": "tsx scripts/test-sse-client.ts",
|
|
36
|
+
"test:published": "tsx scripts/test-published.ts",
|
|
37
|
+
"test:mcp-http": "tsx scripts/test-mcp-http.ts",
|
|
36
38
|
"typecheck": "tsc --noEmit",
|
|
37
39
|
"regen:dev-allowlist": "tsx scripts/dev-allowlist.ts --write",
|
|
38
40
|
"check:dev-allowlist": "tsx scripts/dev-allowlist.ts --check",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* bazi-app.ts — MCP App tool registration for the BaZi Four Pillars Explorer.
|
|
3
|
-
*
|
|
4
|
-
* Registers 1 tool:
|
|
5
|
-
* • explore_bazi_chart — primary entry point, returns data + UI resource [model]
|
|
6
|
-
*
|
|
7
|
-
* Batches three backend API calls in parallel:
|
|
8
|
-
* POST /chinese/bazi → four pillars
|
|
9
|
-
* POST /chinese/bazi/ten-gods → ten gods + hidden stems
|
|
10
|
-
* POST /chinese/bazi/element-balance → wu xing balance + yong shen
|
|
11
|
-
*
|
|
12
|
-
* Merges results into a single UI payload and returns it with a resource URI
|
|
13
|
-
* so the iframe can render the interactive Four Pillars visualization.
|
|
14
|
-
*
|
|
15
|
-
* Also exports resource helpers (getBaziBundle, etc.) for use in
|
|
16
|
-
* index.ts and server-sse.ts.
|
|
17
|
-
*/
|
|
18
|
-
export declare const BAZI_RESOURCE_URI = "ui://openephemeris/bazi";
|
|
19
|
-
export declare const BAZI_MIME_TYPE = "text/html;profile=mcp-app";
|
|
20
|
-
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
21
|
-
export declare function getBaziBundle(): string | null;
|
|
22
|
-
/** Reset cache (useful in dev watch mode or tests). */
|
|
23
|
-
export declare function clearBaziBundleCache(): void;
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* bazi-app.ts — MCP App tool registration for the BaZi Four Pillars Explorer.
|
|
3
|
-
*
|
|
4
|
-
* Registers 1 tool:
|
|
5
|
-
* • explore_bazi_chart — primary entry point, returns data + UI resource [model]
|
|
6
|
-
*
|
|
7
|
-
* Batches three backend API calls in parallel:
|
|
8
|
-
* POST /chinese/bazi → four pillars
|
|
9
|
-
* POST /chinese/bazi/ten-gods → ten gods + hidden stems
|
|
10
|
-
* POST /chinese/bazi/element-balance → wu xing balance + yong shen
|
|
11
|
-
*
|
|
12
|
-
* Merges results into a single UI payload and returns it with a resource URI
|
|
13
|
-
* so the iframe can render the interactive Four Pillars visualization.
|
|
14
|
-
*
|
|
15
|
-
* Also exports resource helpers (getBaziBundle, etc.) for use in
|
|
16
|
-
* index.ts and server-sse.ts.
|
|
17
|
-
*/
|
|
18
|
-
import fs from "node:fs";
|
|
19
|
-
import path from "node:path";
|
|
20
|
-
import { fileURLToPath } from "node:url";
|
|
21
|
-
import { registerTool, SERVER_VERSION } from "../index.js";
|
|
22
|
-
import { getActiveClient } from "../../backend/client.js";
|
|
23
|
-
import { OUTPUT_SCHEMA_JSON } from "../output-schemas.js";
|
|
24
|
-
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
25
|
-
export const BAZI_RESOURCE_URI = "ui://openephemeris/bazi";
|
|
26
|
-
export const BAZI_MIME_TYPE = "text/html;profile=mcp-app";
|
|
27
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
28
|
-
const BUNDLE_PATHS = [
|
|
29
|
-
path.resolve(here, "..", "..", "..", "dist", "ui", "bazi.html"),
|
|
30
|
-
];
|
|
31
|
-
function findBundlePath() {
|
|
32
|
-
for (const p of BUNDLE_PATHS) {
|
|
33
|
-
if (fs.existsSync(p))
|
|
34
|
-
return p;
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
let cachedBundle = null;
|
|
39
|
-
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
40
|
-
export function getBaziBundle() {
|
|
41
|
-
if (cachedBundle)
|
|
42
|
-
return cachedBundle;
|
|
43
|
-
const bundlePath = findBundlePath();
|
|
44
|
-
if (!bundlePath)
|
|
45
|
-
return null;
|
|
46
|
-
try {
|
|
47
|
-
cachedBundle = fs.readFileSync(bundlePath, "utf-8");
|
|
48
|
-
return cachedBundle;
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/** Reset cache (useful in dev watch mode or tests). */
|
|
55
|
-
export function clearBaziBundleCache() {
|
|
56
|
-
cachedBundle = null;
|
|
57
|
-
}
|
|
58
|
-
function parseBaziArgs(args) {
|
|
59
|
-
let { year, month, day, hour } = args;
|
|
60
|
-
if (args.datetime && (!year || !month || !day)) {
|
|
61
|
-
const dt = new Date(args.datetime);
|
|
62
|
-
if (!isNaN(dt.getTime())) {
|
|
63
|
-
year = dt.getUTCFullYear();
|
|
64
|
-
month = dt.getUTCMonth() + 1;
|
|
65
|
-
day = dt.getUTCDate();
|
|
66
|
-
if (hour == null)
|
|
67
|
-
hour = dt.getUTCHours();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (!year || !month || !day) {
|
|
71
|
-
throw new Error("Provide year/month/day fields, or a datetime ISO string. " +
|
|
72
|
-
"Example: year=1987, month=7, day=15 OR datetime='1987-07-15T14:00:00Z'");
|
|
73
|
-
}
|
|
74
|
-
const out = { year, month, day };
|
|
75
|
-
if (hour != null)
|
|
76
|
-
out.hour = hour;
|
|
77
|
-
return out;
|
|
78
|
-
}
|
|
79
|
-
// ── Summary builder ──────────────────────────────────────────────────────────
|
|
80
|
-
function buildBaziSummary(data) {
|
|
81
|
-
const chart = data.chart;
|
|
82
|
-
const balance = data.element_balance;
|
|
83
|
-
const tenGods = data.ten_gods;
|
|
84
|
-
const dm = chart?.day_master;
|
|
85
|
-
const dmStr = dm ? (dm.stem || "?") + " " + (dm.element || "?") : "Unknown";
|
|
86
|
-
let summary = "**BaZi Four Pillars** — Day Master: **" + dmStr + "**\n\n";
|
|
87
|
-
// Pillars summary
|
|
88
|
-
const keys = ["year", "month", "day", "hour"];
|
|
89
|
-
const labels = ["Year", "Month", "Day", "Hour"];
|
|
90
|
-
if (chart) {
|
|
91
|
-
summary += "| Pillar | Stem | Branch | Animal |\n|--------|------|--------|--------|\n";
|
|
92
|
-
for (let i = 0; i < keys.length; i++) {
|
|
93
|
-
const p = chart[keys[i]];
|
|
94
|
-
if (p) {
|
|
95
|
-
summary +=
|
|
96
|
-
"| " + labels[i] +
|
|
97
|
-
" | " + (p.stem?.name || "?") +
|
|
98
|
-
" (" + (p.stem?.element || "") + ")" +
|
|
99
|
-
" | " + (p.branch?.name || "?") +
|
|
100
|
-
" | " + (p.branch?.animal || "") +
|
|
101
|
-
" |\n";
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
summary += "\n";
|
|
105
|
-
}
|
|
106
|
-
// Element balance
|
|
107
|
-
if (balance?.elements) {
|
|
108
|
-
const strength = balance.day_master_strength || "unknown";
|
|
109
|
-
summary += "**Day Master Strength**: " + strength + "\n";
|
|
110
|
-
if (balance.yong_shen_element) {
|
|
111
|
-
summary += "**Useful God (用神)**: " + balance.yong_shen_element + "\n";
|
|
112
|
-
}
|
|
113
|
-
summary += "\n";
|
|
114
|
-
}
|
|
115
|
-
summary += "Click pillars on the chart for Ten Gods detail and interpretation.";
|
|
116
|
-
return summary;
|
|
117
|
-
}
|
|
118
|
-
// ── Tool: explore_bazi_chart ─────────────────────────────────────────────────
|
|
119
|
-
registerTool({
|
|
120
|
-
name: "explore_bazi_chart",
|
|
121
|
-
description: "Generate an interactive BaZi Four Pillars (四柱命盘) visualization. " +
|
|
122
|
-
"Displays the Year, Month, Day, and Hour pillars with Heavenly Stems, " +
|
|
123
|
-
"Earthly Branches, Hidden Stems, Ten Gods analysis, and a weighted " +
|
|
124
|
-
"Wu Xing (Five Elements) balance bar.\n\n" +
|
|
125
|
-
"Returns a rich interactive chart with:\n" +
|
|
126
|
-
" • Four-column pillar grid with Chinese characters and element colours\n" +
|
|
127
|
-
" • Day Master emphasis and badge\n" +
|
|
128
|
-
" • Hidden Stems with strength indicators (main/secondary/residual)\n" +
|
|
129
|
-
" • Ten Gods classification for each pillar\n" +
|
|
130
|
-
" • Wu Xing balance bar with percentages and Yong Shen (Useful God)\n" +
|
|
131
|
-
" • Click pillars for detailed Ten Gods drawer\n\n" +
|
|
132
|
-
"CREDIT COST: 3 credits (batches three BaZi endpoints).\n\n" +
|
|
133
|
-
"Use this for a rich, interactive BaZi experience in MCP Apps-capable hosts (Claude Desktop). " +
|
|
134
|
-
"Falls back to a markdown table summary in other hosts.",
|
|
135
|
-
inputSchema: {
|
|
136
|
-
type: "object",
|
|
137
|
-
properties: {
|
|
138
|
-
year: {
|
|
139
|
-
type: "integer",
|
|
140
|
-
description: "Gregorian birth year, e.g. 1987.",
|
|
141
|
-
},
|
|
142
|
-
month: {
|
|
143
|
-
type: "integer",
|
|
144
|
-
description: "Birth month (1–12).",
|
|
145
|
-
},
|
|
146
|
-
day: {
|
|
147
|
-
type: "integer",
|
|
148
|
-
description: "Birth day of month (1–31).",
|
|
149
|
-
},
|
|
150
|
-
hour: {
|
|
151
|
-
type: "integer",
|
|
152
|
-
description: "Birth hour (0–23). Optional, defaults to 12 (noon). " +
|
|
153
|
-
"Chinese shí hours are 2-hour blocks — precision within a 2-hour window is sufficient.",
|
|
154
|
-
},
|
|
155
|
-
datetime: {
|
|
156
|
-
type: "string",
|
|
157
|
-
description: "Alternative to year/month/day: ISO 8601 datetime (e.g. '1987-07-15T14:00:00Z'). " +
|
|
158
|
-
"year/month/day/hour are extracted automatically.",
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
required: [],
|
|
162
|
-
additionalProperties: false,
|
|
163
|
-
},
|
|
164
|
-
outputSchema: OUTPUT_SCHEMA_JSON,
|
|
165
|
-
annotations: {
|
|
166
|
-
title: "Interactive BaZi Four Pillars Explorer",
|
|
167
|
-
readOnlyHint: true,
|
|
168
|
-
destructiveHint: false,
|
|
169
|
-
idempotentHint: true,
|
|
170
|
-
openWorldHint: false,
|
|
171
|
-
},
|
|
172
|
-
_meta: {
|
|
173
|
-
ui: {
|
|
174
|
-
resourceUri: BAZI_RESOURCE_URI,
|
|
175
|
-
visibility: ["model", "app"],
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
handler: async (args) => {
|
|
179
|
-
const components = parseBaziArgs(args);
|
|
180
|
-
const client = getActiveClient();
|
|
181
|
-
const body = {
|
|
182
|
-
year: components.year,
|
|
183
|
-
month: components.month,
|
|
184
|
-
day: components.day,
|
|
185
|
-
};
|
|
186
|
-
if (components.hour != null)
|
|
187
|
-
body.hour = components.hour;
|
|
188
|
-
// Batch all three BaZi endpoints in parallel
|
|
189
|
-
const [chartResult, tenGodsResult, balanceResult] = await Promise.allSettled([
|
|
190
|
-
client.request("POST", "/chinese/bazi", { data: body }),
|
|
191
|
-
client.request("POST", "/chinese/bazi/ten-gods", { data: body }),
|
|
192
|
-
client.request("POST", "/chinese/bazi/element-balance", { data: body }),
|
|
193
|
-
]);
|
|
194
|
-
const chartData = chartResult.status === "fulfilled"
|
|
195
|
-
? chartResult.value
|
|
196
|
-
: { error: chartResult.reason?.message };
|
|
197
|
-
const tenGodsData = tenGodsResult.status === "fulfilled"
|
|
198
|
-
? tenGodsResult.value
|
|
199
|
-
: { error: tenGodsResult.reason?.message };
|
|
200
|
-
const balanceData = balanceResult.status === "fulfilled"
|
|
201
|
-
? balanceResult.value
|
|
202
|
-
: { error: balanceResult.reason?.message };
|
|
203
|
-
const uiPayload = {
|
|
204
|
-
chart: chartData,
|
|
205
|
-
ten_gods: tenGodsData,
|
|
206
|
-
element_balance: balanceData,
|
|
207
|
-
server_version: SERVER_VERSION,
|
|
208
|
-
};
|
|
209
|
-
const summary = buildBaziSummary(uiPayload);
|
|
210
|
-
const bundleAvailable = Boolean(getBaziBundle());
|
|
211
|
-
if (bundleAvailable) {
|
|
212
|
-
return {
|
|
213
|
-
content: [
|
|
214
|
-
{ type: "text", text: summary },
|
|
215
|
-
{ type: "text", text: JSON.stringify(uiPayload) },
|
|
216
|
-
],
|
|
217
|
-
_meta: {
|
|
218
|
-
"ui/resourceUri": BAZI_RESOURCE_URI,
|
|
219
|
-
ui: { resourceUri: BAZI_RESOURCE_URI },
|
|
220
|
-
},
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
// Fallback: text summary only
|
|
224
|
-
return { content: [{ type: "text", text: summary }] };
|
|
225
|
-
},
|
|
226
|
-
});
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* transit-timeline-app.ts — MCP App tool registration for the Transit Timeline Explorer.
|
|
3
|
-
*
|
|
4
|
-
* Registers 1 tool:
|
|
5
|
-
* • explore_transit_timeline — primary entry point, returns data + UI resource [model]
|
|
6
|
-
*
|
|
7
|
-
* The timeline is rendered client-side from structured JSON — the tool reuses
|
|
8
|
-
* the existing `ephemeris_transits` handler logic to compute natal chart positions
|
|
9
|
-
* and search for transit events, then returns the data with a UI resource link
|
|
10
|
-
* so the iframe can render a Gantt-style timeline.
|
|
11
|
-
*
|
|
12
|
-
* Also exports resource helpers (getTransitTimelineBundle, etc.) for use in
|
|
13
|
-
* index.ts and server-sse.ts.
|
|
14
|
-
*/
|
|
15
|
-
export declare const TRANSIT_TIMELINE_RESOURCE_URI = "ui://openephemeris/transit-timeline";
|
|
16
|
-
export declare const TRANSIT_TIMELINE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
17
|
-
/** Read the pre-built HTML bundle. Returns null if not yet built. */
|
|
18
|
-
export declare function getTransitTimelineBundle(): string | null;
|
|
19
|
-
/** Reset cache (useful in dev watch mode or tests). */
|
|
20
|
-
export declare function clearTransitTimelineBundleCache(): void;
|