@openephemeris/mcp-server 3.12.0 → 3.13.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/README.md +2 -2
- package/dist/index.js +46 -27
- package/dist/server-sse.js +46 -27
- package/dist/tools/apps/bi-wheel-app.d.ts +38 -0
- package/dist/tools/apps/bi-wheel-app.js +459 -0
- package/dist/tools/apps/bodygraph-app.d.ts +22 -0
- package/dist/tools/apps/bodygraph-app.js +633 -0
- package/dist/tools/index.d.ts +1 -20
- package/dist/tools/index.js +12 -0
- package/dist/ui/bi-wheel.html +81 -0
- package/dist/ui/bodygraph.html +514 -0
- package/dist/ui/chart-wheel.html +136 -40
- package/package.json +2 -2
package/dist/tools/index.d.ts
CHANGED
|
@@ -54,23 +54,4 @@ export declare function validateCoordinates(args: any, latKey: string, lonKey: s
|
|
|
54
54
|
* Intercepts embedded VisualResult objects (include_visual=true) and returns dual content.
|
|
55
55
|
* Applies a safety limit to JSON payloads to prevent crashing LLM contexts.
|
|
56
56
|
*/
|
|
57
|
-
export declare function formatToolResponse(toolName: string, result: any, durationMs: number):
|
|
58
|
-
content: ({
|
|
59
|
-
type: string;
|
|
60
|
-
data: string;
|
|
61
|
-
mimeType: string;
|
|
62
|
-
text?: undefined;
|
|
63
|
-
} | {
|
|
64
|
-
type: string;
|
|
65
|
-
text: string;
|
|
66
|
-
data?: undefined;
|
|
67
|
-
mimeType?: undefined;
|
|
68
|
-
})[];
|
|
69
|
-
isError?: undefined;
|
|
70
|
-
} | {
|
|
71
|
-
content: {
|
|
72
|
-
type: string;
|
|
73
|
-
text: string;
|
|
74
|
-
}[];
|
|
75
|
-
isError: boolean;
|
|
76
|
-
};
|
|
57
|
+
export declare function formatToolResponse(toolName: string, result: any, durationMs: number): any;
|
package/dist/tools/index.js
CHANGED
|
@@ -58,6 +58,8 @@ export async function initTools(profile) {
|
|
|
58
58
|
await import("./specialized/acg.js");
|
|
59
59
|
// MCP App tools (interactive UI)
|
|
60
60
|
await import("./apps/chart-wheel-app.js");
|
|
61
|
+
await import("./apps/bodygraph-app.js");
|
|
62
|
+
await import("./apps/bi-wheel-app.js");
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
@@ -90,6 +92,16 @@ export function validateCoordinates(args, latKey, lonKey) {
|
|
|
90
92
|
* Applies a safety limit to JSON payloads to prevent crashing LLM contexts.
|
|
91
93
|
*/
|
|
92
94
|
export function formatToolResponse(toolName, result, durationMs) {
|
|
95
|
+
// Case: handler already returned a pre-formed MCP content array (e.g. app tools like
|
|
96
|
+
// explore_bi_wheel that build { content: [...], _meta: {...} } themselves).
|
|
97
|
+
if (result &&
|
|
98
|
+
typeof result === "object" &&
|
|
99
|
+
Array.isArray(result.content) &&
|
|
100
|
+
result.content.length > 0 &&
|
|
101
|
+
typeof result.content[0]?.type === "string") {
|
|
102
|
+
console.error(`[MCP] ✅ Success (pre-formed): ${toolName} (${durationMs}ms)`);
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
93
105
|
// Case: data response with embedded visual (include_visual=true)
|
|
94
106
|
// VisualResult.data for SVG is a raw string; for PNG it is already base64.
|
|
95
107
|
if (result &&
|
|
@@ -0,0 +1,81 @@
|
|
|
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
|
+
<title>Bi-Wheel Explorer</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<style>:root{--bg:#faf9f5;--surface:#fff;--text:#1a1a2e;--text-secondary:#5a5a7a;--accent:#6366f1;--accent-hover:#4f46e5;--accent-subtle:#6366f11f;--border:#e8e6f0;--border-strong:#c8c4d8;--shadow:0 4px 16px #00000014;--shadow-md:0 8px 32px #0000001f;--radius:10px;--radius-sm:6px;--inner-glyph:#4a3a8a;--inner-tick:#7060b8;--inner-ring:#f2ede6;--inner-stroke:#c0b8a8;--outer-glyph:#92650a;--outer-tick:#c8860e;--outer-ring:#fdf5e4;--outer-stroke:#d4ac60;--xasp-conjunction:#9a7fd4;--xasp-opposition:#e05252;--xasp-trine:#52a8e0;--xasp-square:#e08a52;--xasp-sextile:#52c07a}@media (prefers-color-scheme:dark){:root{--bg:#0d1117;--surface:#161b22;--text:#e6edf3;--text-secondary:#8b949e;--accent:#818cf8;--accent-hover:#a5b4fc;--accent-subtle:#818cf826;--border:#21262d;--border-strong:#30363d;--shadow:0 4px 16px #0006;--shadow-md:0 8px 32px #0009;--inner-glyph:#b0a0e8;--inner-tick:#9080c8;--outer-glyph:#fbbf24;--outer-tick:#d97706;--inner-ring:#1a1628;--outer-ring:#1c1810;--inner-stroke:#3a3460;--outer-stroke:#6b5210}}*,:before,:after{box-sizing:border-box;margin:0;padding:0}html,body{height:100%}body{background:var(--bg);color:var(--text);-webkit-user-select:none;user-select:none;font-family:-apple-system,Inter,Segoe UI,system-ui,sans-serif;font-size:13px;line-height:1.5;overflow:hidden}#app{flex-direction:column;height:100vh;display:flex;position:relative}#loading-state{color:var(--text-secondary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:12px;display:flex}.spinner{border:3px solid var(--border);border-top-color:var(--accent);border-radius:50%;width:32px;height:32px;animation:.8s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}#chart-container{flex:1;justify-content:center;align-items:center;min-height:0;padding:12px;display:flex;position:relative}#chart-container svg{width:auto;max-width:100%;height:auto;max-height:100%}#mode-badge{border-top:1px solid var(--border);background:var(--surface);flex-shrink:0;justify-content:center;align-items:center;gap:10px;padding:6px 14px;font-size:11px;display:flex}.mode-badge-inner{color:var(--inner-glyph);align-items:center;gap:5px;font-weight:600;display:inline-flex}.mode-badge-outer{color:var(--outer-glyph);align-items:center;gap:5px;font-weight:600;display:inline-flex}.mode-badge-sep{color:var(--text-secondary);font-weight:400}.mode-badge-dot-inner{background:var(--inner-tick);border-radius:50%;flex-shrink:0;width:9px;height:9px}.mode-badge-dot-outer{background:var(--outer-tick);border-radius:50%;flex-shrink:0;width:9px;height:9px}.hit-region{cursor:pointer;fill:#0000;stroke:#0000;transition:fill .15s,stroke .15s,opacity .2s}.hit-region:hover{fill:var(--accent-subtle);stroke:var(--accent);stroke-width:1px;stroke-opacity:.5}.hit-region.planet-hit{rx:12px;ry:12px}.hit-region.dim{opacity:.12}.hit-region.aspect-hit{stroke-width:13px}.info-panel{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius);box-shadow:var(--shadow-md);z-index:900;opacity:0;pointer-events:none;width:min(360px,92vw);padding:14px 16px 12px;transition:opacity .18s,transform .18s;position:fixed;bottom:56px;left:50%;transform:translate(-50%)translateY(12px)}.info-panel.visible{opacity:1;pointer-events:all;transform:translate(-50%)translateY(0)}.info-header{align-items:flex-start;gap:10px;margin-bottom:12px;display:flex}.info-glyph{text-align:center;flex-shrink:0;width:32px;font-size:26px;line-height:1}.info-title{color:var(--text);flex:1;font-size:13px;font-weight:700}.info-subtitle{color:var(--text-secondary);margin-top:2px;font-size:11px;font-weight:400}.wheel-badge{white-space:nowrap;border-radius:99px;align-items:center;gap:3px;padding:1px 7px;font-size:10px;font-weight:600;line-height:1.6;display:inline-flex}.wheel-badge.inner{color:var(--inner-glyph);background:#7060b826;border:1px solid #7060b859}.wheel-badge.outer{color:var(--outer-glyph);background:#c8860e26;border:1px solid #c8860e59}.info-close{cursor:pointer;color:var(--text-secondary);background:0 0;border:none;border-radius:4px;flex-shrink:0;padding:2px 4px;font-size:13px;line-height:1;transition:color .12s}.info-close:hover{color:var(--text)}.aspects-title{text-transform:uppercase;letter-spacing:.08em;color:var(--text-secondary);margin-bottom:6px;font-size:10px;font-weight:700}.aspects-list{flex-direction:column;gap:4px;max-height:130px;display:flex;overflow-y:auto}.aspect-row{align-items:center;gap:7px;padding:3px 0;font-size:12px;display:flex}.aspect-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.aspect-sym{text-align:center;flex-shrink:0;width:16px;font-size:14px}.aspect-other{color:var(--text);flex:1}.aspect-meta{color:var(--text-secondary);white-space:nowrap;font-size:11px}.no-aspects{color:var(--text-secondary);padding:4px 0;font-size:11px;font-style:italic}.info-hint{color:var(--accent);text-align:center;margin-top:10px;font-size:10px;font-style:italic}.tooltip{background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--radius);pointer-events:none;box-shadow:var(--shadow-md);z-index:1000;opacity:0;max-width:240px;padding:8px 12px;font-size:12px;transition:opacity .12s;position:fixed}.tooltip.visible{opacity:1}.tooltip-title{color:var(--text);margin-bottom:2px;font-weight:700}.tooltip-detail{color:var(--text-secondary);line-height:1.4}.tooltip-hint{color:var(--accent);margin-top:4px;font-size:10px;font-style:italic}.error-state{text-align:center;color:var(--text-secondary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px;display:flex}.error-state .error-icon{margin-bottom:4px;font-size:32px}.error-state .error-msg{color:var(--text-secondary);text-align:center;max-width:280px;font-size:13px;line-height:1.5}#chart-hint{text-align:center;color:var(--text-secondary);letter-spacing:.03em;opacity:.75;flex-shrink:0;padding:4px 12px 6px;font-size:10px}
|
|
10
|
+
/*$vite$:1*/</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="app">
|
|
14
|
+
<div id="loading-state">
|
|
15
|
+
<div class="spinner"></div>
|
|
16
|
+
<p>Loading bi-wheel…</p>
|
|
17
|
+
</div>
|
|
18
|
+
<div id="chart-container" hidden></div>
|
|
19
|
+
<div id="mode-badge" hidden></div>
|
|
20
|
+
<div id="tooltip" class="tooltip" aria-live="polite"></div>
|
|
21
|
+
<div id="chart-hint" class="chart-hint">Click any planet or aspect line to explore · Press Esc to close</div>
|
|
22
|
+
</div>
|
|
23
|
+
<script type="module">(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=250,t=250,n=240,r=204,i=190,a=159,o=140,s=134,c=290,l=246,u=264,d=16;function f(n,r,i){let a=-(n-i+180)*Math.PI/180;return{x:e+r*Math.cos(a),y:t+r*Math.sin(a)}}function p(e){return document.createElementNS(`http://www.w3.org/2000/svg`,e)}var m={sun:`☉`,moon:`☽`,mercury:`☿`,venus:`♀`,mars:`♂`,jupiter:`♃`,saturn:`♄`,uranus:`♅`,neptune:`♆`,pluto:`♇`,"north node":`☊`,"south node":`☋`,chiron:`⚷`,"true node":`☊`,north_node:`☊`,south_node:`☋`,true_node:`☊`,asc:`AC`,mc:`MC`},h=[`♈`,`♉`,`♊`,`♋`,`♌`,`♍`,`♎`,`♏`,`♐`,`♑`,`♒`,`♓`],g=[`Aries`,`Taurus`,`Gemini`,`Cancer`,`Leo`,`Virgo`,`Libra`,`Scorpio`,`Sagittarius`,`Capricorn`,`Aquarius`,`Pisces`],_={conjunction:`☌`,opposition:`☍`,trine:`△`,square:`□`,sextile:`⚹`},v={conjunction:`#9a7fd4`,opposition:`#e05252`,trine:`#52a8e0`,square:`#e08a52`,sextile:`#52c07a`},y=[`#e8854c`,`#7aaa6a`,`#5aaad0`,`#8878c8`,`#e8854c`,`#7aaa6a`,`#5aaad0`,`#8878c8`,`#e8854c`,`#7aaa6a`,`#5aaad0`,`#8878c8`],b=new Set([`sun`,`moon`,`mercury`,`venus`,`mars`,`jupiter`,`saturn`,`uranus`,`neptune`,`pluto`,`chiron`,`north node`,`south node`,`true node`,`north_node`,`south_node`,`true_node`,`asc`,`mc`]);function x(e){let t=(e%360+360)%360,n=Math.floor(t/30),r=Math.floor(t%30);return`${r}°${Math.floor((t%30-r)*60).toString().padStart(2,`0`)}′ ${g[n]}`}function S(e){return e.replace(/\b\w/g,e=>e.toUpperCase())}function C(e){return String(e).replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`)}function w(e){return Array.isArray(e)?e.filter(e=>e&&typeof e.longitude==`number`&&isFinite(e.longitude)):e&&typeof e==`object`?Object.entries(e).filter(([e])=>b.has(e.toLowerCase())).map(([e,t])=>({name:e.toLowerCase(),longitude:t.longitude??t.lon??0,speed:t.longitude_speed??t.speed,retrograde:!!(t.is_retrograde??t.retrograde),sign:t.sign_name??t.sign,house:t.house})):[]}var T=[{type:`conjunction`,angle:0,orb:8},{type:`opposition`,angle:180,orb:8},{type:`trine`,angle:120,orb:6},{type:`square`,angle:90,orb:5},{type:`sextile`,angle:60,orb:4}];function ee(e,t){let n=[];for(let r of e)for(let e of t){let t=Math.abs(r.longitude-e.longitude)%360;t>180&&(t=360-t);for(let i of T){let a=Math.abs(t-i.angle);if(a<=i.orb){let o=(r.speed??1)-(e.speed??0)<0?t<i.angle:t>i.angle;n.push({planet1:r.name,wheel1:`inner`,planet2:e.name,wheel2:`outer`,type:i.type,angle:i.angle,orb:Math.round(a*100)/100,applying:o});break}}}return n.sort((e,t)=>e.orb-t.orb).slice(0,30)}var E=null;function D(){return E||=document.getElementById(`tooltip`),E}function O(e,t,n,r,i){let a=D();a.innerHTML=`
|
|
24
|
+
<div class="tooltip-title">${n}</div>
|
|
25
|
+
<div class="tooltip-detail">${r}</div>
|
|
26
|
+
${i?`<div class="tooltip-hint">${i}</div>`:``}
|
|
27
|
+
`;let o=e+14,s=t+10;o+240>window.innerWidth&&(o=e-240-8),s+80>window.innerHeight&&(s=t-80-8),a.style.left=`${o}px`,a.style.top=`${s}px`,a.classList.add(`visible`)}function k(){D().classList.remove(`visible`)}var A=null,j=null,M=null,N=new Map;function P(e){return`${e.planet1}|inner|${e.planet2}|outer|${e.type}`}function F(){return A||(A=document.createElement(`div`),A.id=`bi-info-panel`,A.className=`info-panel`,document.body.appendChild(A),A)}function I(){A?.classList.remove(`visible`)}function L(e,t,n,r){let i=F(),a=m[e.name.toLowerCase()]??`★`,o=h[Math.floor((e.longitude%360+360)%360/30)]??``,s=t===`inner`?`Inner · Natal`:r===`transit`?`Outer · Transit`:`Outer · Synastry`,c=t,l=n.filter(n=>t===`inner`&&n.planet1===e.name||t===`outer`&&n.planet2===e.name).sort((e,t)=>e.orb-t.orb),u=l.length?l.map(e=>{let n=t===`inner`?e.planet2:e.planet1,i=m[n.toLowerCase()]??n,a=_[e.type?.toLowerCase()??``]??e.type??`—`,o=v[e.type?.toLowerCase()??``]??`#888`,s=`${e.orb.toFixed(1)}°`,c=r===`transit`?e.applying?`↗`:`↘`:e.orb<=1?`exact`:e.orb<=3?`tight`:`wide`;return`<div class="aspect-row">
|
|
28
|
+
<span class="aspect-dot" style="background:${o}"></span>
|
|
29
|
+
<span class="aspect-sym" style="color:${o}">${a}</span>
|
|
30
|
+
<span class="aspect-other">${C(i)} ${C(S(n))}</span>
|
|
31
|
+
<span class="aspect-meta">${s} ${c}</span>
|
|
32
|
+
</div>`}).join(``):`<div class="no-aspects">No cross-aspects within orb</div>`;i.innerHTML=`
|
|
33
|
+
<div class="info-header">
|
|
34
|
+
<span class="info-glyph">${C(a)}</span>
|
|
35
|
+
<div class="info-title">
|
|
36
|
+
<div style="display:flex;align-items:center;gap:6px;flex-wrap:wrap;">
|
|
37
|
+
<strong>${C(S(e.name))}</strong>
|
|
38
|
+
${e.retrograde?`<span style='color:#e05252'>℞</span>`:``}
|
|
39
|
+
<span class="wheel-badge ${c}">${C(s)}</span>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="info-subtitle">${C(o)} ${C(x(e.longitude))}${e.house?` · House ${e.house}`:``}</div>
|
|
42
|
+
</div>
|
|
43
|
+
<button class="info-close" id="bi-info-close-btn">✕</button>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="aspects-title">Cross-Aspects</div>
|
|
46
|
+
<div class="aspects-list">${u}</div>
|
|
47
|
+
<div class="info-hint">Click a cross-aspect line for full interpretation</div>
|
|
48
|
+
`,i.classList.add(`visible`),document.getElementById(`bi-info-close-btn`)?.addEventListener(`click`,()=>{I(),B()})}function te(e,t){let n=F(),r=m[e.planet1.toLowerCase()]??`★`,i=m[e.planet2.toLowerCase()]??`★`,a=_[e.type?.toLowerCase()??``]??e.type,o=v[e.type?.toLowerCase()??``]??`#888`,s=S(e.planet1),c=t===`transit`?`Tr. ${S(e.planet2)}`:S(e.planet2),l=t===`transit`?e.applying?`↗ Applying`:`↘ Separating`:e.orb<=1?`Exact`:e.orb<=3?`Tight`:`Wide`;n.innerHTML=`
|
|
49
|
+
<div class="info-header">
|
|
50
|
+
<span class="info-glyph" style="color:${o}">${C(String(a))}</span>
|
|
51
|
+
<div class="info-title">
|
|
52
|
+
<div style="display:flex;align-items:center;gap:5px;flex-wrap:wrap;">
|
|
53
|
+
<strong>${C(r)} ${C(s)}</strong>
|
|
54
|
+
<span style="color:${o}">${C(String(a))}</span>
|
|
55
|
+
<strong>${C(i)} ${C(c)}</strong>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="info-subtitle">${e.orb.toFixed(1)}° orb · ${C(l)}</div>
|
|
58
|
+
</div>
|
|
59
|
+
<button class="info-close" id="bi-info-close-btn">✕</button>
|
|
60
|
+
</div>
|
|
61
|
+
<div style="display:flex;gap:6px;margin-bottom:10px;">
|
|
62
|
+
<span class="wheel-badge inner">Inner · ${C(s)}</span>
|
|
63
|
+
<span class="wheel-badge outer">Outer · ${C(c)}</span>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="info-hint">Loading interpretation…</div>
|
|
66
|
+
`,n.classList.add(`visible`),document.getElementById(`bi-info-close-btn`)?.addEventListener(`click`,()=>{I(),B()})}function R(e,t){N.forEach(({vis:n,color:r},i)=>{let a=i.split(`|`);(t===`inner`?a[0]===e:a[2]===e)?(n.style.stroke=r,n.style.strokeOpacity=`0.92`,n.style.strokeWidth=`2`):(n.style.strokeOpacity=`0.05`,n.style.strokeWidth=`0.7`)}),z(e,t)}function ne(e,t){N.forEach(({vis:n,color:r},i)=>{i===e?(n.style.stroke=t,n.style.strokeOpacity=`0.92`,n.style.strokeWidth=`2.5`):(n.style.strokeOpacity=`0.05`,n.style.strokeWidth=`0.7`)})}function z(e,t){M?.querySelectorAll(`.planet-hit`).forEach(n=>{let r=n.dataset.wheel,i=(n.dataset.planet??``)===e&&r===t;n.classList.toggle(`dim`,!i)})}function B(){N.forEach(({vis:e,color:t})=>{e.style.stroke=t,e.style.strokeOpacity=`0.45`,e.style.strokeWidth=`1`}),M?.querySelectorAll(`.planet-hit`).forEach(e=>e.classList.remove(`dim`))}function V(e,t,g,b){let C=t.mode??`synastry`;e.innerHTML=``,N.clear(),I();let T=w(t.inner),E=w(t.outer),D=t.inner_houses??[],A=t.cross_aspects??[];A.length===0&&T.length>0&&E.length>0&&(A=ee(T,E));let F=D[0]?.cusp_lon??t.ascendant??0,z=p(`svg`);z.setAttribute(`viewBox`,`0 0 500 500`),z.setAttribute(`width`,`100%`),z.setAttribute(`height`,`100%`),z.style.display=`block`,e.appendChild(z),M=z;let V=p(`circle`);V.setAttribute(`cx`,`250`),V.setAttribute(`cy`,`250`),V.setAttribute(`r`,`294`),V.style.fill=`var(--bg, #faf9f5)`,V.setAttribute(`stroke`,`#d4cec8`),V.setAttribute(`stroke-width`,`0.5`),V.setAttribute(`pointer-events`,`none`),z.appendChild(V);let H=p(`circle`);H.setAttribute(`cx`,`250`),H.setAttribute(`cy`,`250`),H.setAttribute(`r`,String(c)),H.setAttribute(`fill`,`var(--outer-ring, #fdf5e4)`),H.setAttribute(`stroke`,`var(--outer-stroke, #d4ac60)`),H.setAttribute(`stroke-width`,`0.8`),H.setAttribute(`pointer-events`,`none`),z.appendChild(H);let U=p(`circle`);U.setAttribute(`cx`,`250`),U.setAttribute(`cy`,`250`),U.setAttribute(`r`,String(l)),U.style.fill=`var(--bg, #faf9f5)`,U.setAttribute(`stroke`,`var(--outer-stroke, #d4ac60)`),U.setAttribute(`stroke-width`,`0.8`),U.setAttribute(`pointer-events`,`none`),z.appendChild(U);for(let e=0;e<12;e++){let t=e*30,{x:n,y:r}=f(t,l,F),{x:i,y:a}=f(t,c,F),o=p(`line`);o.setAttribute(`x1`,n.toFixed(1)),o.setAttribute(`y1`,r.toFixed(1)),o.setAttribute(`x2`,i.toFixed(1)),o.setAttribute(`y2`,a.toFixed(1)),o.setAttribute(`stroke`,`var(--outer-stroke, #d4ac60)`),o.setAttribute(`stroke-width`,`0.5`),o.setAttribute(`pointer-events`,`none`),z.appendChild(o);let{x:s,y:u}=f(t+15,(l+c)/2,F),d=p(`text`);d.setAttribute(`x`,s.toFixed(1)),d.setAttribute(`y`,u.toFixed(1)),d.setAttribute(`text-anchor`,`middle`),d.setAttribute(`dominant-baseline`,`central`),d.setAttribute(`font-size`,`12`),d.setAttribute(`fill`,re(y[e])),d.setAttribute(`pointer-events`,`none`),d.style.fontFamily=`serif`,d.textContent=h[e],z.appendChild(d)}let W=p(`circle`);W.setAttribute(`cx`,`250`),W.setAttribute(`cy`,`250`),W.setAttribute(`r`,String(n)),W.setAttribute(`fill`,`var(--inner-ring, #f2ede6)`),W.setAttribute(`stroke`,`var(--inner-stroke, #c0b8a8)`),W.setAttribute(`stroke-width`,`0.5`),W.setAttribute(`pointer-events`,`none`),z.appendChild(W);let G=p(`circle`);G.setAttribute(`cx`,`250`),G.setAttribute(`cy`,`250`),G.setAttribute(`r`,String(r)),G.style.fill=`var(--bg, #faf9f5)`,G.setAttribute(`stroke`,`var(--inner-stroke, #c0b8a8)`),G.setAttribute(`stroke-width`,`0.5`),G.setAttribute(`pointer-events`,`none`),z.appendChild(G);for(let e=0;e<12;e++){let t=e*30,{x:i,y:a}=f(t,r,F),{x:o,y:s}=f(t,n,F),c=p(`line`);c.setAttribute(`x1`,i.toFixed(1)),c.setAttribute(`y1`,a.toFixed(1)),c.setAttribute(`x2`,o.toFixed(1)),c.setAttribute(`y2`,s.toFixed(1)),c.setAttribute(`stroke`,`var(--inner-stroke, #c0b8a8)`),c.setAttribute(`stroke-width`,`0.5`),c.setAttribute(`pointer-events`,`none`),z.appendChild(c);let{x:l,y:u}=f(t+15,(r+n)/2,F),d=p(`text`);d.setAttribute(`x`,l.toFixed(1)),d.setAttribute(`y`,u.toFixed(1)),d.setAttribute(`text-anchor`,`middle`),d.setAttribute(`dominant-baseline`,`central`),d.setAttribute(`font-size`,`13`),d.setAttribute(`fill`,y[e]),d.setAttribute(`pointer-events`,`none`),d.style.fontFamily=`serif`,d.textContent=h[e],z.appendChild(d)}let K=p(`circle`);if(K.setAttribute(`cx`,`250`),K.setAttribute(`cy`,`250`),K.setAttribute(`r`,String(o)),K.style.fill=`var(--bg, #faf9f5)`,K.setAttribute(`stroke`,`var(--inner-stroke, #c0b8a8)`),K.setAttribute(`stroke-width`,`0.5`),K.setAttribute(`pointer-events`,`none`),z.appendChild(K),D.length>0)for(let e=0;e<D.length;e++){let t=D[e],n=D[(e+1)%D.length],i=[1,4,7,10].includes(t.number),{x:s,y:c}=f(t.cusp_lon,o,F),{x:l,y:u}=f(t.cusp_lon,r,F),d=p(`line`);d.setAttribute(`x1`,s.toFixed(1)),d.setAttribute(`y1`,c.toFixed(1)),d.setAttribute(`x2`,l.toFixed(1)),d.setAttribute(`y2`,u.toFixed(1)),d.setAttribute(`stroke`,i?`#7060b8`:`#a89898`),d.setAttribute(`stroke-width`,i?`1.5`:`0.7`),d.setAttribute(`pointer-events`,`none`),z.appendChild(d);let m=(n.cusp_lon-t.cusp_lon+360)%360,{x:h,y:g}=f(t.cusp_lon+m/2,a,F),_=p(`text`);_.setAttribute(`x`,h.toFixed(1)),_.setAttribute(`y`,g.toFixed(1)),_.setAttribute(`text-anchor`,`middle`),_.setAttribute(`dominant-baseline`,`central`),_.setAttribute(`font-size`,`9`),_.setAttribute(`fill`,i?`#7060b8`:`#90808a`),_.setAttribute(`pointer-events`,`none`),_.textContent=String(t.number),z.appendChild(_)}let q=D.find(e=>e.number===1),J=D.find(e=>e.number===4),Y=D.find(e=>e.number===7),X=D.find(e=>e.number===10),Z=[{lon:q?.cusp_lon??F,label:`ASC`},{lon:Y?.cusp_lon??(F+180)%360,label:`DSC`},{lon:X?.cusp_lon??(F+270)%360,label:`MC`},{lon:J?.cusp_lon??(F+90)%360,label:`IC`}];for(let e of Z){let{x:t,y:n}=f(e.lon,c+12,F),r=p(`text`);r.setAttribute(`x`,t.toFixed(1)),r.setAttribute(`y`,n.toFixed(1)),r.setAttribute(`text-anchor`,`middle`),r.setAttribute(`dominant-baseline`,`central`),r.setAttribute(`font-size`,`8`),r.setAttribute(`font-weight`,`700`),r.setAttribute(`fill`,`#7060b8`),r.setAttribute(`pointer-events`,`none`),r.textContent=e.label,z.appendChild(r)}for(let e of A){let t=T.find(t=>t.name===e.planet1),n=E.find(t=>t.name===e.planet2);if(!t||!n)continue;let r=v[e.type?.toLowerCase()??``]??`#aaa`,{x:i,y:a}=f(t.longitude,s,F),{x:o,y:c}=f(n.longitude,l,F),u=p(`line`);u.setAttribute(`x1`,i.toFixed(1)),u.setAttribute(`y1`,a.toFixed(1)),u.setAttribute(`x2`,o.toFixed(1)),u.setAttribute(`y2`,c.toFixed(1)),u.setAttribute(`stroke-dasharray`,`4 3`),u.setAttribute(`pointer-events`,`none`),u.style.stroke=r,u.style.strokeOpacity=`0.60`,u.style.strokeWidth=`1.3`,z.appendChild(u);let d=p(`line`);d.setAttribute(`x1`,i.toFixed(1)),d.setAttribute(`y1`,a.toFixed(1)),d.setAttribute(`x2`,o.toFixed(1)),d.setAttribute(`y2`,c.toFixed(1)),d.setAttribute(`stroke`,`transparent`),d.setAttribute(`stroke-width`,`13`),d.setAttribute(`fill`,`none`),d.setAttribute(`class`,`hit-region aspect-hit`),d.style.pointerEvents=`all`;let h=m[t.name.toLowerCase()]??t.name,g=m[n.name.toLowerCase()]??n.name,y=_[e.type?.toLowerCase()??``]??e.type??``,x=C===`transit`?e.applying?` (applying)`:` (separating)`:e.orb<=1?` (exact)`:e.orb<=3?` (tight)`:` (wide)`,w=`${h} ${y} ${g} · ${e.orb.toFixed(1)}° orb${x}`;d.addEventListener(`mouseenter`,t=>O(t.clientX,t.clientY,S(e.type??`Cross-Aspect`),w,`Click for interpretation`)),d.addEventListener(`mousemove`,t=>O(t.clientX,t.clientY,S(e.type??`Cross-Aspect`),w,`Click for interpretation`)),d.addEventListener(`mouseleave`,k),d.addEventListener(`click`,()=>{k(),ne(P(e),r),te(e,C),b(e)}),N.set(P(e),{vis:u,color:r}),z.appendChild(d)}for(let e of E){let t=m[e.name.toLowerCase()]??`★`,{x:n,y:r}=f(e.longitude,u,F),{x:i,y:a}=f(e.longitude,l+5,F),o=p(`circle`);o.setAttribute(`cx`,i.toFixed(1)),o.setAttribute(`cy`,a.toFixed(1)),o.setAttribute(`r`,`2.5`),o.setAttribute(`fill`,`var(--outer-tick, #c8860e)`),o.setAttribute(`opacity`,`0.75`),o.setAttribute(`pointer-events`,`none`),z.appendChild(o);let s=p(`text`);s.setAttribute(`x`,n.toFixed(1)),s.setAttribute(`y`,r.toFixed(1)),s.setAttribute(`text-anchor`,`middle`),s.setAttribute(`dominant-baseline`,`central`),s.setAttribute(`font-size`,`14`),s.setAttribute(`pointer-events`,`none`),s.style.fill=`var(--outer-glyph, #92650a)`,s.style.fontFamily=`serif`,s.textContent=t,z.appendChild(s);let c=Math.floor((e.longitude%360+360)%360%30),{x:h,y:_}=f(e.longitude,u-14,F),v=p(`text`);if(v.setAttribute(`x`,h.toFixed(1)),v.setAttribute(`y`,_.toFixed(1)),v.setAttribute(`text-anchor`,`middle`),v.setAttribute(`dominant-baseline`,`central`),v.setAttribute(`font-size`,`7`),v.setAttribute(`fill`,`#b08030`),v.setAttribute(`pointer-events`,`none`),v.textContent=`${c}°`,z.appendChild(v),e.retrograde){let{x:t,y:n}=f(e.longitude,u+13,F),r=p(`text`);r.setAttribute(`x`,t.toFixed(1)),r.setAttribute(`y`,n.toFixed(1)),r.setAttribute(`text-anchor`,`middle`),r.setAttribute(`dominant-baseline`,`central`),r.setAttribute(`font-size`,`8`),r.setAttribute(`fill`,`#e05252`),r.setAttribute(`pointer-events`,`none`),r.textContent=`℞`,z.appendChild(r)}let y=p(`circle`);y.setAttribute(`cx`,n.toFixed(1)),y.setAttribute(`cy`,r.toFixed(1)),y.setAttribute(`r`,String(d)),y.setAttribute(`fill`,`transparent`),y.setAttribute(`class`,`hit-region planet-hit`),y.dataset.planet=e.name.toLowerCase(),y.dataset.wheel=`outer`,y.style.pointerEvents=`all`;let b=`${x(e.longitude)}${e.house?` · H${e.house}`:``}${e.retrograde?` ℞`:``}`;y.addEventListener(`mouseenter`,n=>O(n.clientX,n.clientY,`${t} ${S(e.name)} (outer)`,b,`Click to explore`)),y.addEventListener(`mousemove`,n=>O(n.clientX,n.clientY,`${t} ${S(e.name)} (outer)`,b,`Click to explore`)),y.addEventListener(`mouseleave`,k),y.addEventListener(`click`,()=>{k(),R(e.name,`outer`),L(e,`outer`,A,C),g(e,`outer`)}),z.appendChild(y)}for(let e of T){let t=m[e.name.toLowerCase()]??`★`,{x:n,y:a}=f(e.longitude,i,F),{x:o,y:s}=f(e.longitude,r-5,F),c=p(`circle`);c.setAttribute(`cx`,o.toFixed(1)),c.setAttribute(`cy`,s.toFixed(1)),c.setAttribute(`r`,`2.5`),c.setAttribute(`fill`,`var(--inner-tick, #7060b8)`),c.setAttribute(`opacity`,`0.65`),c.setAttribute(`pointer-events`,`none`),z.appendChild(c);let l=p(`text`);l.setAttribute(`x`,n.toFixed(1)),l.setAttribute(`y`,a.toFixed(1)),l.setAttribute(`text-anchor`,`middle`),l.setAttribute(`dominant-baseline`,`central`),l.setAttribute(`font-size`,`15`),l.setAttribute(`pointer-events`,`none`),l.style.fill=`var(--inner-glyph, #4a3a8a)`,l.style.fontFamily=`serif`,l.textContent=t,z.appendChild(l);let u=Math.floor((e.longitude%360+360)%360%30),{x:h,y:_}=f(e.longitude,i-17,F),v=p(`text`);if(v.setAttribute(`x`,h.toFixed(1)),v.setAttribute(`y`,_.toFixed(1)),v.setAttribute(`text-anchor`,`middle`),v.setAttribute(`dominant-baseline`,`central`),v.setAttribute(`font-size`,`7`),v.setAttribute(`fill`,`#9080a0`),v.setAttribute(`pointer-events`,`none`),v.textContent=`${u}°`,z.appendChild(v),e.retrograde){let{x:t,y:n}=f(e.longitude,i+14,F),r=p(`text`);r.setAttribute(`x`,t.toFixed(1)),r.setAttribute(`y`,n.toFixed(1)),r.setAttribute(`text-anchor`,`middle`),r.setAttribute(`dominant-baseline`,`central`),r.setAttribute(`font-size`,`8`),r.setAttribute(`fill`,`#e05252`),r.setAttribute(`pointer-events`,`none`),r.textContent=`℞`,z.appendChild(r)}let y=p(`circle`);y.setAttribute(`cx`,n.toFixed(1)),y.setAttribute(`cy`,a.toFixed(1)),y.setAttribute(`r`,String(d)),y.setAttribute(`fill`,`transparent`),y.setAttribute(`class`,`hit-region planet-hit`),y.dataset.planet=e.name.toLowerCase(),y.dataset.wheel=`inner`,y.style.pointerEvents=`all`;let b=`${x(e.longitude)}${e.house?` · H${e.house}`:``}${e.retrograde?` ℞`:``}`;y.addEventListener(`mouseenter`,n=>O(n.clientX,n.clientY,`${t} ${S(e.name)} (inner)`,b,`Click to explore`)),y.addEventListener(`mousemove`,n=>O(n.clientX,n.clientY,`${t} ${S(e.name)} (inner)`,b,`Click to explore`)),y.addEventListener(`mouseleave`,k),y.addEventListener(`click`,()=>{k(),R(e.name,`inner`),L(e,`inner`,A,C),g(e,`inner`)}),z.appendChild(y)}j&&document.removeEventListener(`click`,j,!1),j=e=>{let t=e.target;!t.closest(`.hit-region`)&&!t.closest(`#bi-info-panel`)&&(B(),I())},document.addEventListener(`click`,j,!1);let Q=e=>{e.key===`Escape`&&(B(),I())};document.removeEventListener(`keydown`,window.__biWheelEscHandler,!1),window.__biWheelEscHandler=Q,document.addEventListener(`keydown`,Q,!1)}function re(e){let t=parseInt(e.slice(1,3),16),n=parseInt(e.slice(3,5),16),r=parseInt(e.slice(5,7),16),i=.6;return`rgb(${Math.round(t*(1-i)+208*i)},${Math.round(n*(1-i)+144*i)},${Math.round(r*(1-i)+32*i)})`}var H=null,U=!1,W=document.getElementById(`chart-container`),G=document.getElementById(`loading-state`),K=document.getElementById(`mode-badge`);function q(){G.hidden=!1,W.hidden=!0,K.hidden=!0}function J(){G.hidden=!0,W.hidden=!1,K.hidden=!1}function Y(e){G.hidden=!0,W.innerHTML=`
|
|
67
|
+
<div class="error-state">
|
|
68
|
+
<div class="error-icon">⚠️</div>
|
|
69
|
+
<p class="error-msg">${e}</p>
|
|
70
|
+
</div>`,W.hidden=!1}function X(e){for(let t of e.content??[]){if(t.type!==`text`||!t.text)continue;let e=t.text.trim();if(e.startsWith(`{`))try{let t=JSON.parse(e);if(`inner`in t&&`outer`in t)return t}catch{}}return null}function Z(e){let t=e.mode??`synastry`,n=e._birth_params_inner?.location??`Person 1`,r=e._birth_params_outer?.location??(t===`transit`?`Transits`:`Person 2`),i=t===`synastry`?`${n}`:`Natal · ${n}`,a=t===`synastry`?`${r}`:`Transit · ${r}`;K.innerHTML=`
|
|
71
|
+
<span class="mode-badge-inner">
|
|
72
|
+
<span class="mode-badge-dot-inner"></span>
|
|
73
|
+
${Q(i)}
|
|
74
|
+
</span>
|
|
75
|
+
<span class="mode-badge-sep">·</span>
|
|
76
|
+
<span class="mode-badge-outer">
|
|
77
|
+
<span class="mode-badge-dot-outer"></span>
|
|
78
|
+
${Q(a)}
|
|
79
|
+
</span>`}function Q(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`)}function $(e){H=e,Z(e),V(W,e,ie,ae),J()}function ie(e,t){if(U||!window.mcpBridge)return;let n=Math.floor((e.longitude%360+360)%360/30),r=e.sign??[`Aries`,`Taurus`,`Gemini`,`Cancer`,`Leo`,`Virgo`,`Libra`,`Scorpio`,`Sagittarius`,`Capricorn`,`Aquarius`,`Pisces`][n]??`Unknown`;window.mcpBridge.callServerTool(`bi_wheel_on_planet_click`,{planet:e.name,wheel:t,longitude:e.longitude,sign:r,house:e.house??void 0,retrograde:e.retrograde??!1,mode:H?.mode??`synastry`},e=>{})}function ae(e){U||!window.mcpBridge||window.mcpBridge.callServerTool(`bi_wheel_on_cross_aspect_click`,{planet1:e.planet1,wheel1:e.wheel1,planet2:e.planet2,wheel2:e.wheel2,aspect_type:e.type,orb:e.orb,applying:e.applying,mode:H?.mode??`synastry`},e=>{})}function oe(){if(!window.mcpBridge){$(se());return}q(),U=!0,window.mcpBridge.onToolResult(e=>{U=!1;let t=X(e);if(!t){Y(`Ask your AI assistant to generate a bi-wheel chart to get started.`);return}$(t)})}function se(){return{mode:`synastry`,inner:[{name:`sun`,longitude:25.4,house:1,retrograde:!1},{name:`moon`,longitude:110.8,house:4,retrograde:!1},{name:`mercury`,longitude:345.2,house:12,retrograde:!1},{name:`venus`,longitude:58.7,house:2,retrograde:!1},{name:`mars`,longitude:220.1,house:8,retrograde:!1},{name:`jupiter`,longitude:80.6,house:3,retrograde:!1},{name:`saturn`,longitude:175.3,house:7,retrograde:!0},{name:`asc`,longitude:0,house:1,retrograde:!1},{name:`mc`,longitude:270,house:10,retrograde:!1}],outer:[{name:`sun`,longitude:67.1,house:2,retrograde:!1},{name:`moon`,longitude:202.4,house:8,retrograde:!1},{name:`mercury`,longitude:52.8,house:2,retrograde:!0},{name:`venus`,longitude:88.3,house:3,retrograde:!1},{name:`mars`,longitude:301.7,house:11,retrograde:!1},{name:`jupiter`,longitude:256.9,house:9,retrograde:!1},{name:`saturn`,longitude:355.2,house:12,retrograde:!1}],inner_houses:Array.from({length:12},(e,t)=>({number:t+1,cusp_lon:t*30,sign:[`Aries`,`Taurus`,`Gemini`,`Cancer`,`Leo`,`Virgo`,`Libra`,`Scorpio`,`Sagittarius`,`Capricorn`,`Aquarius`,`Pisces`][t]})),cross_aspects:[{planet1:`sun`,wheel1:`inner`,planet2:`moon`,wheel2:`outer`,type:`trine`,angle:120,orb:2.5,applying:!0},{planet1:`mars`,wheel1:`inner`,planet2:`sun`,wheel2:`outer`,type:`opposition`,angle:180,orb:1.8,applying:!1},{planet1:`moon`,wheel1:`inner`,planet2:`venus`,wheel2:`outer`,type:`sextile`,angle:60,orb:3.4,applying:!0}],_birth_params_inner:{datetime:`1990-05-10T14:00:00`,location:`New York, NY`,latitude:40.71,longitude:-74.01,timezone:`America/New_York`},_birth_params_outer:{datetime:`1992-08-22T09:30:00`,location:`Los Angeles, CA`,latitude:34.05,longitude:-118.24,timezone:`America/Los_Angeles`}}}window.addEventListener(`DOMContentLoaded`,()=>{setTimeout(oe,80)});</script>
|
|
80
|
+
</body>
|
|
81
|
+
</html>
|