@useago/sdk 0.3.0 → 0.3.2
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 -0
- package/dist/AgoClient-DPZdN5n2.js +905 -0
- package/dist/AgoClient-DPZdN5n2.js.map +1 -0
- package/dist/AgoClient-wMVUQqCD.cjs +976 -0
- package/dist/AgoClient-wMVUQqCD.cjs.map +1 -0
- package/dist/angular.cjs +138 -100
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.d.ts +1 -0
- package/dist/angular.js +139 -103
- package/dist/angular.js.map +1 -1
- package/dist/client/AgoClient.d.ts +56 -0
- package/dist/client/types.d.ts +5 -1
- package/dist/createMockClient-Ci_N2tH8.cjs +104 -0
- package/dist/createMockClient-Ci_N2tH8.cjs.map +1 -0
- package/dist/createMockClient-U0ae_AYy.js +99 -0
- package/dist/createMockClient-U0ae_AYy.js.map +1 -0
- package/dist/devtools/index.d.ts +2 -0
- package/dist/devtools/initDevPanel.d.ts +15 -0
- package/dist/devtools.cjs +182 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.ts +2 -0
- package/dist/devtools.js +181 -0
- package/dist/devtools.js.map +1 -0
- package/dist/functions--c6lx3ic.cjs +480 -0
- package/dist/functions--c6lx3ic.cjs.map +1 -0
- package/dist/functions-C9F1dnmh.js +398 -0
- package/dist/functions-C9F1dnmh.js.map +1 -0
- package/dist/helpers/factory.d.ts +20 -0
- package/dist/helpers.cjs +14 -305
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js +2 -306
- package/dist/index.cjs +316 -151
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +14 -9
- package/dist/index.js +289 -163
- package/dist/index.js.map +1 -1
- package/dist/react/components/ChatWidget.d.ts +2 -0
- package/dist/react/components/Markdown.d.ts +12 -0
- package/dist/react/components/Message.d.ts +2 -0
- package/dist/react/components/index.d.ts +2 -0
- package/dist/react/context/AgoContext.d.ts +29 -3
- package/dist/react/context/index.d.ts +1 -1
- package/dist/react/hooks/index.d.ts +1 -0
- package/dist/react/hooks/useAgoContext.d.ts +40 -0
- package/dist/react/hooks/useAgoFunction.d.ts +14 -2
- package/dist/react/hooks/useAgoStore.d.ts +17 -0
- package/dist/react/index.d.ts +5 -1
- package/dist/react.cjs +22130 -10274
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +1 -0
- package/dist/react.js +22128 -10289
- package/dist/react.js.map +1 -1
- package/dist/rolldown-runtime-BqCkTl7Q.cjs +50 -0
- package/dist/rolldown-runtime-CNZpIYwj.js +33 -0
- package/dist/state/ClientContextRegistry.d.ts +64 -0
- package/dist/state/createStore.d.ts +30 -0
- package/dist/vue/composables/useAgoStore.d.ts +18 -0
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue.cjs +312 -208
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.ts +1 -0
- package/dist/vue.js +311 -218
- package/dist/vue.js.map +1 -1
- package/dist/widget/types.d.ts +1 -0
- package/dist/widget.cjs +0 -2
- package/dist/widget.d.ts +1 -0
- package/dist/widget.js +0 -2
- package/package.json +6 -1
- package/dist/AgoClient-B-SONi_K.js +0 -861
- package/dist/AgoClient-B-SONi_K.js.map +0 -1
- package/dist/AgoClient-xTWfMWKh.cjs +0 -860
- package/dist/AgoClient-xTWfMWKh.cjs.map +0 -1
- package/dist/createMockClient-B1DcBiIK.js +0 -94
- package/dist/createMockClient-B1DcBiIK.js.map +0 -1
- package/dist/createMockClient-BqNSJUu4.cjs +0 -93
- package/dist/createMockClient-BqNSJUu4.cjs.map +0 -1
- package/dist/helpers.cjs.map +0 -1
- package/dist/helpers.js.map +0 -1
- package/dist/widget.cjs.map +0 -1
- package/dist/widget.js.map +0 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/devtools/initDevPanel.ts
|
|
3
|
+
var stateEl;
|
|
4
|
+
var logEl;
|
|
5
|
+
var getStateFn = () => ({});
|
|
6
|
+
function renderState() {
|
|
7
|
+
if (!stateEl) return;
|
|
8
|
+
stateEl.textContent = JSON.stringify(getStateFn(), null, 2);
|
|
9
|
+
}
|
|
10
|
+
function logLine(text, kind) {
|
|
11
|
+
if (!logEl) return;
|
|
12
|
+
const line = document.createElement("div");
|
|
13
|
+
line.className = `dev-log-line dev-log-${kind}`;
|
|
14
|
+
line.textContent = `${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${text}`;
|
|
15
|
+
logEl.appendChild(line);
|
|
16
|
+
logEl.scrollTop = logEl.scrollHeight;
|
|
17
|
+
}
|
|
18
|
+
var COLLAPSE_KEY = "devPanelCollapsed";
|
|
19
|
+
function setCollapsed(panel, collapsed) {
|
|
20
|
+
panel.classList.toggle("collapsed", collapsed);
|
|
21
|
+
const toggle = panel.querySelector(".dev-toggle");
|
|
22
|
+
if (toggle) {
|
|
23
|
+
toggle.textContent = collapsed ? "▢" : "—";
|
|
24
|
+
toggle.title = collapsed ? "Expand dev tools" : "Collapse dev tools";
|
|
25
|
+
toggle.setAttribute("aria-expanded", String(!collapsed));
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
localStorage.setItem(COLLAPSE_KEY, collapsed ? "1" : "0");
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
function initDevPanel(options) {
|
|
32
|
+
const { store, client, target } = options;
|
|
33
|
+
getStateFn = store.get;
|
|
34
|
+
injectStyles();
|
|
35
|
+
const host = typeof target === "string" ? document.querySelector(target) : target instanceof Element ? target : document.body;
|
|
36
|
+
const panel = document.createElement("aside");
|
|
37
|
+
panel.id = "dev-panel";
|
|
38
|
+
(host ?? document.body).appendChild(panel);
|
|
39
|
+
panel.innerHTML = `
|
|
40
|
+
<div class="dev-head">
|
|
41
|
+
<span class="dev-badge">DEV</span>
|
|
42
|
+
<span class="dev-title">DEV TOOLS · client-side function state — not for production</span>
|
|
43
|
+
<button type="button" class="dev-toggle" aria-label="Toggle dev tools">—</button>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="dev-body">
|
|
46
|
+
<div class="dev-fns">Registered functions: <code>${(client.getRegisteredFunctions?.() ?? []).map((f) => f.name).join(", ") || "—"}</code></div>
|
|
47
|
+
<div class="dev-section-label">JSON object (built by the agent)</div>
|
|
48
|
+
<pre class="dev-state" id="dev-state"></pre>
|
|
49
|
+
<div class="dev-section-label">Function calls</div>
|
|
50
|
+
<div class="dev-log" id="dev-log"></div>
|
|
51
|
+
</div>
|
|
52
|
+
`;
|
|
53
|
+
stateEl = panel.querySelector("#dev-state");
|
|
54
|
+
logEl = panel.querySelector("#dev-log");
|
|
55
|
+
panel.querySelector(".dev-toggle")?.addEventListener("click", (e) => {
|
|
56
|
+
e.stopPropagation();
|
|
57
|
+
setCollapsed(panel, !panel.classList.contains("collapsed"));
|
|
58
|
+
});
|
|
59
|
+
panel.addEventListener("click", () => {
|
|
60
|
+
if (panel.classList.contains("collapsed")) setCollapsed(panel, false);
|
|
61
|
+
});
|
|
62
|
+
let startCollapsed = false;
|
|
63
|
+
try {
|
|
64
|
+
startCollapsed = localStorage.getItem(COLLAPSE_KEY) === "1";
|
|
65
|
+
} catch {}
|
|
66
|
+
setCollapsed(panel, startCollapsed);
|
|
67
|
+
client.on("function:invoke", ({ functionName, arguments: args }) => {
|
|
68
|
+
logLine(`→ ${functionName}(${JSON.stringify(args ?? {})})`, "invoke");
|
|
69
|
+
});
|
|
70
|
+
client.on("function:result", ({ result, error }) => {
|
|
71
|
+
logLine(error ? `✗ error: ${error}` : `← ${JSON.stringify(result)}`, error ? "error" : "result");
|
|
72
|
+
});
|
|
73
|
+
store.subscribe(renderState);
|
|
74
|
+
renderState();
|
|
75
|
+
}
|
|
76
|
+
var STYLE_ID = "dev-panel-styles";
|
|
77
|
+
function injectStyles() {
|
|
78
|
+
if (document.getElementById(STYLE_ID)) return;
|
|
79
|
+
const style = document.createElement("style");
|
|
80
|
+
style.id = STYLE_ID;
|
|
81
|
+
style.textContent = PANEL_CSS;
|
|
82
|
+
document.head.appendChild(style);
|
|
83
|
+
}
|
|
84
|
+
var PANEL_CSS = `
|
|
85
|
+
#dev-panel {
|
|
86
|
+
position: fixed;
|
|
87
|
+
top: 16px;
|
|
88
|
+
right: 16px;
|
|
89
|
+
width: min(360px, calc(100vw - 32px));
|
|
90
|
+
max-width: calc(100vw - 32px);
|
|
91
|
+
box-sizing: border-box;
|
|
92
|
+
max-height: calc(100vh - 32px);
|
|
93
|
+
display: flex;
|
|
94
|
+
flex-direction: column;
|
|
95
|
+
gap: 8px;
|
|
96
|
+
padding: 12px 14px;
|
|
97
|
+
background: #0f1419;
|
|
98
|
+
color: #d7e0e8;
|
|
99
|
+
border: 1px solid #2a3441;
|
|
100
|
+
border-radius: 12px;
|
|
101
|
+
box-shadow: 0 20px 50px -20px rgba(0,0,0,.6);
|
|
102
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
103
|
+
font-size: 12px;
|
|
104
|
+
z-index: 1000;
|
|
105
|
+
}
|
|
106
|
+
#dev-panel .dev-head { display: flex; align-items: center; gap: 8px; }
|
|
107
|
+
#dev-panel .dev-toggle {
|
|
108
|
+
margin-left: auto;
|
|
109
|
+
flex: none;
|
|
110
|
+
width: 22px;
|
|
111
|
+
height: 22px;
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
justify-content: center;
|
|
115
|
+
background: transparent;
|
|
116
|
+
color: #7c8a99;
|
|
117
|
+
border: 1px solid #2a3441;
|
|
118
|
+
border-radius: 6px;
|
|
119
|
+
font-size: 12px;
|
|
120
|
+
line-height: 1;
|
|
121
|
+
cursor: pointer;
|
|
122
|
+
}
|
|
123
|
+
#dev-panel .dev-toggle:hover { color: #d7e0e8; border-color: #3a4655; }
|
|
124
|
+
#dev-panel .dev-body { display: flex; flex-direction: column; gap: 8px; }
|
|
125
|
+
|
|
126
|
+
/* Collapsed: shrink to a small clickable widget showing only the DEV badge. */
|
|
127
|
+
#dev-panel.collapsed {
|
|
128
|
+
width: auto;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
padding: 8px 10px;
|
|
131
|
+
}
|
|
132
|
+
#dev-panel.collapsed .dev-title,
|
|
133
|
+
#dev-panel.collapsed .dev-body { display: none; }
|
|
134
|
+
#dev-panel.collapsed .dev-toggle { margin-left: 6px; }
|
|
135
|
+
#dev-panel .dev-badge {
|
|
136
|
+
background: #f59e0b;
|
|
137
|
+
color: #1c1206;
|
|
138
|
+
font-weight: 700;
|
|
139
|
+
font-size: 10px;
|
|
140
|
+
letter-spacing: .08em;
|
|
141
|
+
padding: 2px 6px;
|
|
142
|
+
border-radius: 5px;
|
|
143
|
+
}
|
|
144
|
+
#dev-panel .dev-title { color: #f59e0b; font-size: 11px; line-height: 1.3; }
|
|
145
|
+
#dev-panel .dev-fns { color: #7c8a99; font-size: 11px; }
|
|
146
|
+
#dev-panel .dev-fns code { color: #9ecbff; }
|
|
147
|
+
#dev-panel .dev-section-label {
|
|
148
|
+
color: #7c8a99;
|
|
149
|
+
text-transform: uppercase;
|
|
150
|
+
letter-spacing: .08em;
|
|
151
|
+
font-size: 10px;
|
|
152
|
+
margin-top: 4px;
|
|
153
|
+
}
|
|
154
|
+
#dev-panel .dev-state {
|
|
155
|
+
margin: 0;
|
|
156
|
+
padding: 8px;
|
|
157
|
+
background: #060a0e;
|
|
158
|
+
border-radius: 8px;
|
|
159
|
+
overflow: auto;
|
|
160
|
+
max-height: 40vh;
|
|
161
|
+
white-space: pre;
|
|
162
|
+
color: #c8e6c9;
|
|
163
|
+
}
|
|
164
|
+
#dev-panel .dev-log {
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
gap: 2px;
|
|
168
|
+
overflow-y: auto;
|
|
169
|
+
max-height: 24vh;
|
|
170
|
+
background: #060a0e;
|
|
171
|
+
border-radius: 8px;
|
|
172
|
+
padding: 6px 8px;
|
|
173
|
+
}
|
|
174
|
+
#dev-panel .dev-log-line { white-space: pre-wrap; word-break: break-word; line-height: 1.4; }
|
|
175
|
+
#dev-panel .dev-log-invoke { color: #9ecbff; }
|
|
176
|
+
#dev-panel .dev-log-result { color: #86efac; }
|
|
177
|
+
#dev-panel .dev-log-error { color: #fca5a5; }
|
|
178
|
+
`;
|
|
179
|
+
//#endregion
|
|
180
|
+
exports.initDevPanel = initDevPanel;
|
|
181
|
+
|
|
182
|
+
//# sourceMappingURL=devtools.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.cjs","names":[],"sources":["../src/devtools/initDevPanel.ts"],"sourcesContent":["import type { AgoClient } from \"../client/AgoClient\";\nimport type { Store } from \"../state/createStore\";\n\n/** Options for {@link initDevPanel}. */\nexport interface DevPanelOptions {\n /** The store whose state the panel renders live. */\n store: Store<unknown>;\n /**\n * Client to read registered functions from and listen to function events on.\n * Typed structurally so a mock client works too.\n */\n client: Pick<AgoClient, \"on\" | \"getRegisteredFunctions\">;\n /** Where to mount: a CSS selector, an Element, or `document.body` (default). */\n target?: string | Element;\n}\n\nlet stateEl: HTMLElement | null;\nlet logEl: HTMLElement | null;\nlet getStateFn: () => unknown = () => ({});\n\n// Re-render the JSON object. Wired to the store's subscribe() in initDevPanel.\nfunction renderState(): void {\n if (!stateEl) return;\n stateEl.textContent = JSON.stringify(getStateFn(), null, 2);\n}\n\nfunction logLine(text: string, kind: \"invoke\" | \"result\" | \"error\"): void {\n if (!logEl) return;\n const line = document.createElement(\"div\");\n line.className = `dev-log-line dev-log-${kind}`;\n const time = new Date().toLocaleTimeString();\n line.textContent = `${time} ${text}`;\n logEl.appendChild(line);\n logEl.scrollTop = logEl.scrollHeight;\n}\n\nconst COLLAPSE_KEY = \"devPanelCollapsed\";\n\nfunction setCollapsed(panel: HTMLElement, collapsed: boolean): void {\n panel.classList.toggle(\"collapsed\", collapsed);\n const toggle = panel.querySelector<HTMLButtonElement>(\".dev-toggle\");\n if (toggle) {\n toggle.textContent = collapsed ? \"▢\" : \"—\";\n toggle.title = collapsed ? \"Expand dev tools\" : \"Collapse dev tools\";\n toggle.setAttribute(\"aria-expanded\", String(!collapsed));\n }\n try {\n localStorage.setItem(COLLAPSE_KEY, collapsed ? \"1\" : \"0\");\n } catch {\n // localStorage may be unavailable; collapse state just won't persist.\n }\n}\n\nexport function initDevPanel(options: DevPanelOptions): void {\n const { store, client, target } = options;\n getStateFn = store.get;\n injectStyles();\n const host =\n typeof target === \"string\"\n ? document.querySelector(target)\n : target instanceof Element\n ? target\n : document.body;\n const panel = document.createElement(\"aside\");\n panel.id = \"dev-panel\";\n (host ?? document.body).appendChild(panel);\n\n const registered = client.getRegisteredFunctions?.() ?? [];\n const fnNames = registered.map((f) => f.name).join(\", \") || \"—\";\n\n panel.innerHTML = `\n <div class=\"dev-head\">\n <span class=\"dev-badge\">DEV</span>\n <span class=\"dev-title\">DEV TOOLS · client-side function state — not for production</span>\n <button type=\"button\" class=\"dev-toggle\" aria-label=\"Toggle dev tools\">—</button>\n </div>\n <div class=\"dev-body\">\n <div class=\"dev-fns\">Registered functions: <code>${fnNames}</code></div>\n <div class=\"dev-section-label\">JSON object (built by the agent)</div>\n <pre class=\"dev-state\" id=\"dev-state\"></pre>\n <div class=\"dev-section-label\">Function calls</div>\n <div class=\"dev-log\" id=\"dev-log\"></div>\n </div>\n `;\n\n stateEl = panel.querySelector<HTMLElement>(\"#dev-state\");\n logEl = panel.querySelector<HTMLElement>(\"#dev-log\");\n\n const toggle = panel.querySelector<HTMLButtonElement>(\".dev-toggle\");\n toggle?.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n setCollapsed(panel, !panel.classList.contains(\"collapsed\"));\n });\n // When collapsed, the whole widget acts as an expand button.\n panel.addEventListener(\"click\", () => {\n if (panel.classList.contains(\"collapsed\")) setCollapsed(panel, false);\n });\n\n let startCollapsed = false;\n try {\n startCollapsed = localStorage.getItem(COLLAPSE_KEY) === \"1\";\n } catch {\n // ignore\n }\n setCollapsed(panel, startCollapsed);\n\n client.on(\"function:invoke\", ({ functionName, arguments: args }) => {\n logLine(`→ ${functionName}(${JSON.stringify(args ?? {})})`, \"invoke\");\n });\n client.on(\"function:result\", ({ result, error }) => {\n logLine(\n error ? `✗ error: ${error}` : `← ${JSON.stringify(result)}`,\n error ? \"error\" : \"result\",\n );\n });\n\n // Re-render the JSON object on every state change, then paint the initial state.\n store.subscribe(renderState);\n renderState();\n}\n\nconst STYLE_ID = \"dev-panel-styles\";\n\nfunction injectStyles(): void {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = PANEL_CSS;\n document.head.appendChild(style);\n}\n\nconst PANEL_CSS = `\n#dev-panel {\n position: fixed;\n top: 16px;\n right: 16px;\n width: min(360px, calc(100vw - 32px));\n max-width: calc(100vw - 32px);\n box-sizing: border-box;\n max-height: calc(100vh - 32px);\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px 14px;\n background: #0f1419;\n color: #d7e0e8;\n border: 1px solid #2a3441;\n border-radius: 12px;\n box-shadow: 0 20px 50px -20px rgba(0,0,0,.6);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n z-index: 1000;\n}\n#dev-panel .dev-head { display: flex; align-items: center; gap: 8px; }\n#dev-panel .dev-toggle {\n margin-left: auto;\n flex: none;\n width: 22px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n color: #7c8a99;\n border: 1px solid #2a3441;\n border-radius: 6px;\n font-size: 12px;\n line-height: 1;\n cursor: pointer;\n}\n#dev-panel .dev-toggle:hover { color: #d7e0e8; border-color: #3a4655; }\n#dev-panel .dev-body { display: flex; flex-direction: column; gap: 8px; }\n\n/* Collapsed: shrink to a small clickable widget showing only the DEV badge. */\n#dev-panel.collapsed {\n width: auto;\n cursor: pointer;\n padding: 8px 10px;\n}\n#dev-panel.collapsed .dev-title,\n#dev-panel.collapsed .dev-body { display: none; }\n#dev-panel.collapsed .dev-toggle { margin-left: 6px; }\n#dev-panel .dev-badge {\n background: #f59e0b;\n color: #1c1206;\n font-weight: 700;\n font-size: 10px;\n letter-spacing: .08em;\n padding: 2px 6px;\n border-radius: 5px;\n}\n#dev-panel .dev-title { color: #f59e0b; font-size: 11px; line-height: 1.3; }\n#dev-panel .dev-fns { color: #7c8a99; font-size: 11px; }\n#dev-panel .dev-fns code { color: #9ecbff; }\n#dev-panel .dev-section-label {\n color: #7c8a99;\n text-transform: uppercase;\n letter-spacing: .08em;\n font-size: 10px;\n margin-top: 4px;\n}\n#dev-panel .dev-state {\n margin: 0;\n padding: 8px;\n background: #060a0e;\n border-radius: 8px;\n overflow: auto;\n max-height: 40vh;\n white-space: pre;\n color: #c8e6c9;\n}\n#dev-panel .dev-log {\n display: flex;\n flex-direction: column;\n gap: 2px;\n overflow-y: auto;\n max-height: 24vh;\n background: #060a0e;\n border-radius: 8px;\n padding: 6px 8px;\n}\n#dev-panel .dev-log-line { white-space: pre-wrap; word-break: break-word; line-height: 1.4; }\n#dev-panel .dev-log-invoke { color: #9ecbff; }\n#dev-panel .dev-log-result { color: #86efac; }\n#dev-panel .dev-log-error { color: #fca5a5; }\n`;\n"],"mappings":";;AAgBA,IAAI;AACJ,IAAI;AACJ,IAAI,oBAAmC,EAAE;AAGzC,SAAS,cAAoB;AAC3B,KAAI,CAAC,QAAS;AACd,SAAQ,cAAc,KAAK,UAAU,YAAY,EAAE,MAAM,EAAE;;AAG7D,SAAS,QAAQ,MAAc,MAA2C;AACxE,KAAI,CAAC,MAAO;CACZ,MAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,MAAK,YAAY,wBAAwB;AAEzC,MAAK,cAAc,oBADN,IAAI,MAAM,EAAC,oBACF,CAAK,IAAI;AAC/B,OAAM,YAAY,KAAK;AACvB,OAAM,YAAY,MAAM;;AAG1B,IAAM,eAAe;AAErB,SAAS,aAAa,OAAoB,WAA0B;AAClE,OAAM,UAAU,OAAO,aAAa,UAAU;CAC9C,MAAM,SAAS,MAAM,cAAiC,cAAc;AACpE,KAAI,QAAQ;AACV,SAAO,cAAc,YAAY,MAAM;AACvC,SAAO,QAAQ,YAAY,qBAAqB;AAChD,SAAO,aAAa,iBAAiB,OAAO,CAAC,UAAU,CAAC;;AAE1D,KAAI;AACF,eAAa,QAAQ,cAAc,YAAY,MAAM,IAAI;SACnD;;AAKV,SAAgB,aAAa,SAAgC;CAC3D,MAAM,EAAE,OAAO,QAAQ,WAAW;AAClC,cAAa,MAAM;AACnB,eAAc;CACd,MAAM,OACJ,OAAO,WAAW,WACd,SAAS,cAAc,OAAO,GAC9B,kBAAkB,UAChB,SACA,SAAS;CACjB,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,OAAM,KAAK;AACX,EAAC,QAAQ,SAAS,MAAM,YAAY,MAAM;AAK1C,OAAM,YAAY;;;;;;;0DAHC,OAAO,0BAA0B,IAAI,EAAE,EAC/B,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK,IAAI,IASG;;;;;;;AAQ/D,WAAU,MAAM,cAA2B,aAAa;AACxD,SAAQ,MAAM,cAA2B,WAAW;AAErC,OAAM,cAAiC,cACtD,EAAQ,iBAAiB,UAAU,MAAM;AACvC,IAAE,iBAAiB;AACnB,eAAa,OAAO,CAAC,MAAM,UAAU,SAAS,YAAY,CAAC;GAC3D;AAEF,OAAM,iBAAiB,eAAe;AACpC,MAAI,MAAM,UAAU,SAAS,YAAY,CAAE,cAAa,OAAO,MAAM;GACrE;CAEF,IAAI,iBAAiB;AACrB,KAAI;AACF,mBAAiB,aAAa,QAAQ,aAAa,KAAK;SAClD;AAGR,cAAa,OAAO,eAAe;AAEnC,QAAO,GAAG,oBAAoB,EAAE,cAAc,WAAW,WAAW;AAClE,UAAQ,KAAK,aAAa,GAAG,KAAK,UAAU,QAAQ,EAAE,CAAC,CAAC,IAAI,SAAS;GACrE;AACF,QAAO,GAAG,oBAAoB,EAAE,QAAQ,YAAY;AAClD,UACE,QAAQ,YAAY,UAAU,KAAK,KAAK,UAAU,OAAO,IACzD,QAAQ,UAAU,SACnB;GACD;AAGF,OAAM,UAAU,YAAY;AAC5B,cAAa;;AAGf,IAAM,WAAW;AAEjB,SAAS,eAAqB;AAC5B,KAAI,SAAS,eAAe,SAAS,CAAE;CACvC,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,OAAM,KAAK;AACX,OAAM,cAAc;AACpB,UAAS,KAAK,YAAY,MAAM;;AAGlC,IAAM,YAAY"}
|
package/dist/devtools.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
//#region src/devtools/initDevPanel.ts
|
|
2
|
+
var stateEl;
|
|
3
|
+
var logEl;
|
|
4
|
+
var getStateFn = () => ({});
|
|
5
|
+
function renderState() {
|
|
6
|
+
if (!stateEl) return;
|
|
7
|
+
stateEl.textContent = JSON.stringify(getStateFn(), null, 2);
|
|
8
|
+
}
|
|
9
|
+
function logLine(text, kind) {
|
|
10
|
+
if (!logEl) return;
|
|
11
|
+
const line = document.createElement("div");
|
|
12
|
+
line.className = `dev-log-line dev-log-${kind}`;
|
|
13
|
+
line.textContent = `${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${text}`;
|
|
14
|
+
logEl.appendChild(line);
|
|
15
|
+
logEl.scrollTop = logEl.scrollHeight;
|
|
16
|
+
}
|
|
17
|
+
var COLLAPSE_KEY = "devPanelCollapsed";
|
|
18
|
+
function setCollapsed(panel, collapsed) {
|
|
19
|
+
panel.classList.toggle("collapsed", collapsed);
|
|
20
|
+
const toggle = panel.querySelector(".dev-toggle");
|
|
21
|
+
if (toggle) {
|
|
22
|
+
toggle.textContent = collapsed ? "▢" : "—";
|
|
23
|
+
toggle.title = collapsed ? "Expand dev tools" : "Collapse dev tools";
|
|
24
|
+
toggle.setAttribute("aria-expanded", String(!collapsed));
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
localStorage.setItem(COLLAPSE_KEY, collapsed ? "1" : "0");
|
|
28
|
+
} catch {}
|
|
29
|
+
}
|
|
30
|
+
function initDevPanel(options) {
|
|
31
|
+
const { store, client, target } = options;
|
|
32
|
+
getStateFn = store.get;
|
|
33
|
+
injectStyles();
|
|
34
|
+
const host = typeof target === "string" ? document.querySelector(target) : target instanceof Element ? target : document.body;
|
|
35
|
+
const panel = document.createElement("aside");
|
|
36
|
+
panel.id = "dev-panel";
|
|
37
|
+
(host ?? document.body).appendChild(panel);
|
|
38
|
+
panel.innerHTML = `
|
|
39
|
+
<div class="dev-head">
|
|
40
|
+
<span class="dev-badge">DEV</span>
|
|
41
|
+
<span class="dev-title">DEV TOOLS · client-side function state — not for production</span>
|
|
42
|
+
<button type="button" class="dev-toggle" aria-label="Toggle dev tools">—</button>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="dev-body">
|
|
45
|
+
<div class="dev-fns">Registered functions: <code>${(client.getRegisteredFunctions?.() ?? []).map((f) => f.name).join(", ") || "—"}</code></div>
|
|
46
|
+
<div class="dev-section-label">JSON object (built by the agent)</div>
|
|
47
|
+
<pre class="dev-state" id="dev-state"></pre>
|
|
48
|
+
<div class="dev-section-label">Function calls</div>
|
|
49
|
+
<div class="dev-log" id="dev-log"></div>
|
|
50
|
+
</div>
|
|
51
|
+
`;
|
|
52
|
+
stateEl = panel.querySelector("#dev-state");
|
|
53
|
+
logEl = panel.querySelector("#dev-log");
|
|
54
|
+
panel.querySelector(".dev-toggle")?.addEventListener("click", (e) => {
|
|
55
|
+
e.stopPropagation();
|
|
56
|
+
setCollapsed(panel, !panel.classList.contains("collapsed"));
|
|
57
|
+
});
|
|
58
|
+
panel.addEventListener("click", () => {
|
|
59
|
+
if (panel.classList.contains("collapsed")) setCollapsed(panel, false);
|
|
60
|
+
});
|
|
61
|
+
let startCollapsed = false;
|
|
62
|
+
try {
|
|
63
|
+
startCollapsed = localStorage.getItem(COLLAPSE_KEY) === "1";
|
|
64
|
+
} catch {}
|
|
65
|
+
setCollapsed(panel, startCollapsed);
|
|
66
|
+
client.on("function:invoke", ({ functionName, arguments: args }) => {
|
|
67
|
+
logLine(`→ ${functionName}(${JSON.stringify(args ?? {})})`, "invoke");
|
|
68
|
+
});
|
|
69
|
+
client.on("function:result", ({ result, error }) => {
|
|
70
|
+
logLine(error ? `✗ error: ${error}` : `← ${JSON.stringify(result)}`, error ? "error" : "result");
|
|
71
|
+
});
|
|
72
|
+
store.subscribe(renderState);
|
|
73
|
+
renderState();
|
|
74
|
+
}
|
|
75
|
+
var STYLE_ID = "dev-panel-styles";
|
|
76
|
+
function injectStyles() {
|
|
77
|
+
if (document.getElementById(STYLE_ID)) return;
|
|
78
|
+
const style = document.createElement("style");
|
|
79
|
+
style.id = STYLE_ID;
|
|
80
|
+
style.textContent = PANEL_CSS;
|
|
81
|
+
document.head.appendChild(style);
|
|
82
|
+
}
|
|
83
|
+
var PANEL_CSS = `
|
|
84
|
+
#dev-panel {
|
|
85
|
+
position: fixed;
|
|
86
|
+
top: 16px;
|
|
87
|
+
right: 16px;
|
|
88
|
+
width: min(360px, calc(100vw - 32px));
|
|
89
|
+
max-width: calc(100vw - 32px);
|
|
90
|
+
box-sizing: border-box;
|
|
91
|
+
max-height: calc(100vh - 32px);
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
gap: 8px;
|
|
95
|
+
padding: 12px 14px;
|
|
96
|
+
background: #0f1419;
|
|
97
|
+
color: #d7e0e8;
|
|
98
|
+
border: 1px solid #2a3441;
|
|
99
|
+
border-radius: 12px;
|
|
100
|
+
box-shadow: 0 20px 50px -20px rgba(0,0,0,.6);
|
|
101
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
102
|
+
font-size: 12px;
|
|
103
|
+
z-index: 1000;
|
|
104
|
+
}
|
|
105
|
+
#dev-panel .dev-head { display: flex; align-items: center; gap: 8px; }
|
|
106
|
+
#dev-panel .dev-toggle {
|
|
107
|
+
margin-left: auto;
|
|
108
|
+
flex: none;
|
|
109
|
+
width: 22px;
|
|
110
|
+
height: 22px;
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
justify-content: center;
|
|
114
|
+
background: transparent;
|
|
115
|
+
color: #7c8a99;
|
|
116
|
+
border: 1px solid #2a3441;
|
|
117
|
+
border-radius: 6px;
|
|
118
|
+
font-size: 12px;
|
|
119
|
+
line-height: 1;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
}
|
|
122
|
+
#dev-panel .dev-toggle:hover { color: #d7e0e8; border-color: #3a4655; }
|
|
123
|
+
#dev-panel .dev-body { display: flex; flex-direction: column; gap: 8px; }
|
|
124
|
+
|
|
125
|
+
/* Collapsed: shrink to a small clickable widget showing only the DEV badge. */
|
|
126
|
+
#dev-panel.collapsed {
|
|
127
|
+
width: auto;
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
padding: 8px 10px;
|
|
130
|
+
}
|
|
131
|
+
#dev-panel.collapsed .dev-title,
|
|
132
|
+
#dev-panel.collapsed .dev-body { display: none; }
|
|
133
|
+
#dev-panel.collapsed .dev-toggle { margin-left: 6px; }
|
|
134
|
+
#dev-panel .dev-badge {
|
|
135
|
+
background: #f59e0b;
|
|
136
|
+
color: #1c1206;
|
|
137
|
+
font-weight: 700;
|
|
138
|
+
font-size: 10px;
|
|
139
|
+
letter-spacing: .08em;
|
|
140
|
+
padding: 2px 6px;
|
|
141
|
+
border-radius: 5px;
|
|
142
|
+
}
|
|
143
|
+
#dev-panel .dev-title { color: #f59e0b; font-size: 11px; line-height: 1.3; }
|
|
144
|
+
#dev-panel .dev-fns { color: #7c8a99; font-size: 11px; }
|
|
145
|
+
#dev-panel .dev-fns code { color: #9ecbff; }
|
|
146
|
+
#dev-panel .dev-section-label {
|
|
147
|
+
color: #7c8a99;
|
|
148
|
+
text-transform: uppercase;
|
|
149
|
+
letter-spacing: .08em;
|
|
150
|
+
font-size: 10px;
|
|
151
|
+
margin-top: 4px;
|
|
152
|
+
}
|
|
153
|
+
#dev-panel .dev-state {
|
|
154
|
+
margin: 0;
|
|
155
|
+
padding: 8px;
|
|
156
|
+
background: #060a0e;
|
|
157
|
+
border-radius: 8px;
|
|
158
|
+
overflow: auto;
|
|
159
|
+
max-height: 40vh;
|
|
160
|
+
white-space: pre;
|
|
161
|
+
color: #c8e6c9;
|
|
162
|
+
}
|
|
163
|
+
#dev-panel .dev-log {
|
|
164
|
+
display: flex;
|
|
165
|
+
flex-direction: column;
|
|
166
|
+
gap: 2px;
|
|
167
|
+
overflow-y: auto;
|
|
168
|
+
max-height: 24vh;
|
|
169
|
+
background: #060a0e;
|
|
170
|
+
border-radius: 8px;
|
|
171
|
+
padding: 6px 8px;
|
|
172
|
+
}
|
|
173
|
+
#dev-panel .dev-log-line { white-space: pre-wrap; word-break: break-word; line-height: 1.4; }
|
|
174
|
+
#dev-panel .dev-log-invoke { color: #9ecbff; }
|
|
175
|
+
#dev-panel .dev-log-result { color: #86efac; }
|
|
176
|
+
#dev-panel .dev-log-error { color: #fca5a5; }
|
|
177
|
+
`;
|
|
178
|
+
//#endregion
|
|
179
|
+
export { initDevPanel };
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=devtools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.js","names":[],"sources":["../src/devtools/initDevPanel.ts"],"sourcesContent":["import type { AgoClient } from \"../client/AgoClient\";\nimport type { Store } from \"../state/createStore\";\n\n/** Options for {@link initDevPanel}. */\nexport interface DevPanelOptions {\n /** The store whose state the panel renders live. */\n store: Store<unknown>;\n /**\n * Client to read registered functions from and listen to function events on.\n * Typed structurally so a mock client works too.\n */\n client: Pick<AgoClient, \"on\" | \"getRegisteredFunctions\">;\n /** Where to mount: a CSS selector, an Element, or `document.body` (default). */\n target?: string | Element;\n}\n\nlet stateEl: HTMLElement | null;\nlet logEl: HTMLElement | null;\nlet getStateFn: () => unknown = () => ({});\n\n// Re-render the JSON object. Wired to the store's subscribe() in initDevPanel.\nfunction renderState(): void {\n if (!stateEl) return;\n stateEl.textContent = JSON.stringify(getStateFn(), null, 2);\n}\n\nfunction logLine(text: string, kind: \"invoke\" | \"result\" | \"error\"): void {\n if (!logEl) return;\n const line = document.createElement(\"div\");\n line.className = `dev-log-line dev-log-${kind}`;\n const time = new Date().toLocaleTimeString();\n line.textContent = `${time} ${text}`;\n logEl.appendChild(line);\n logEl.scrollTop = logEl.scrollHeight;\n}\n\nconst COLLAPSE_KEY = \"devPanelCollapsed\";\n\nfunction setCollapsed(panel: HTMLElement, collapsed: boolean): void {\n panel.classList.toggle(\"collapsed\", collapsed);\n const toggle = panel.querySelector<HTMLButtonElement>(\".dev-toggle\");\n if (toggle) {\n toggle.textContent = collapsed ? \"▢\" : \"—\";\n toggle.title = collapsed ? \"Expand dev tools\" : \"Collapse dev tools\";\n toggle.setAttribute(\"aria-expanded\", String(!collapsed));\n }\n try {\n localStorage.setItem(COLLAPSE_KEY, collapsed ? \"1\" : \"0\");\n } catch {\n // localStorage may be unavailable; collapse state just won't persist.\n }\n}\n\nexport function initDevPanel(options: DevPanelOptions): void {\n const { store, client, target } = options;\n getStateFn = store.get;\n injectStyles();\n const host =\n typeof target === \"string\"\n ? document.querySelector(target)\n : target instanceof Element\n ? target\n : document.body;\n const panel = document.createElement(\"aside\");\n panel.id = \"dev-panel\";\n (host ?? document.body).appendChild(panel);\n\n const registered = client.getRegisteredFunctions?.() ?? [];\n const fnNames = registered.map((f) => f.name).join(\", \") || \"—\";\n\n panel.innerHTML = `\n <div class=\"dev-head\">\n <span class=\"dev-badge\">DEV</span>\n <span class=\"dev-title\">DEV TOOLS · client-side function state — not for production</span>\n <button type=\"button\" class=\"dev-toggle\" aria-label=\"Toggle dev tools\">—</button>\n </div>\n <div class=\"dev-body\">\n <div class=\"dev-fns\">Registered functions: <code>${fnNames}</code></div>\n <div class=\"dev-section-label\">JSON object (built by the agent)</div>\n <pre class=\"dev-state\" id=\"dev-state\"></pre>\n <div class=\"dev-section-label\">Function calls</div>\n <div class=\"dev-log\" id=\"dev-log\"></div>\n </div>\n `;\n\n stateEl = panel.querySelector<HTMLElement>(\"#dev-state\");\n logEl = panel.querySelector<HTMLElement>(\"#dev-log\");\n\n const toggle = panel.querySelector<HTMLButtonElement>(\".dev-toggle\");\n toggle?.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n setCollapsed(panel, !panel.classList.contains(\"collapsed\"));\n });\n // When collapsed, the whole widget acts as an expand button.\n panel.addEventListener(\"click\", () => {\n if (panel.classList.contains(\"collapsed\")) setCollapsed(panel, false);\n });\n\n let startCollapsed = false;\n try {\n startCollapsed = localStorage.getItem(COLLAPSE_KEY) === \"1\";\n } catch {\n // ignore\n }\n setCollapsed(panel, startCollapsed);\n\n client.on(\"function:invoke\", ({ functionName, arguments: args }) => {\n logLine(`→ ${functionName}(${JSON.stringify(args ?? {})})`, \"invoke\");\n });\n client.on(\"function:result\", ({ result, error }) => {\n logLine(\n error ? `✗ error: ${error}` : `← ${JSON.stringify(result)}`,\n error ? \"error\" : \"result\",\n );\n });\n\n // Re-render the JSON object on every state change, then paint the initial state.\n store.subscribe(renderState);\n renderState();\n}\n\nconst STYLE_ID = \"dev-panel-styles\";\n\nfunction injectStyles(): void {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = PANEL_CSS;\n document.head.appendChild(style);\n}\n\nconst PANEL_CSS = `\n#dev-panel {\n position: fixed;\n top: 16px;\n right: 16px;\n width: min(360px, calc(100vw - 32px));\n max-width: calc(100vw - 32px);\n box-sizing: border-box;\n max-height: calc(100vh - 32px);\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px 14px;\n background: #0f1419;\n color: #d7e0e8;\n border: 1px solid #2a3441;\n border-radius: 12px;\n box-shadow: 0 20px 50px -20px rgba(0,0,0,.6);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n z-index: 1000;\n}\n#dev-panel .dev-head { display: flex; align-items: center; gap: 8px; }\n#dev-panel .dev-toggle {\n margin-left: auto;\n flex: none;\n width: 22px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n color: #7c8a99;\n border: 1px solid #2a3441;\n border-radius: 6px;\n font-size: 12px;\n line-height: 1;\n cursor: pointer;\n}\n#dev-panel .dev-toggle:hover { color: #d7e0e8; border-color: #3a4655; }\n#dev-panel .dev-body { display: flex; flex-direction: column; gap: 8px; }\n\n/* Collapsed: shrink to a small clickable widget showing only the DEV badge. */\n#dev-panel.collapsed {\n width: auto;\n cursor: pointer;\n padding: 8px 10px;\n}\n#dev-panel.collapsed .dev-title,\n#dev-panel.collapsed .dev-body { display: none; }\n#dev-panel.collapsed .dev-toggle { margin-left: 6px; }\n#dev-panel .dev-badge {\n background: #f59e0b;\n color: #1c1206;\n font-weight: 700;\n font-size: 10px;\n letter-spacing: .08em;\n padding: 2px 6px;\n border-radius: 5px;\n}\n#dev-panel .dev-title { color: #f59e0b; font-size: 11px; line-height: 1.3; }\n#dev-panel .dev-fns { color: #7c8a99; font-size: 11px; }\n#dev-panel .dev-fns code { color: #9ecbff; }\n#dev-panel .dev-section-label {\n color: #7c8a99;\n text-transform: uppercase;\n letter-spacing: .08em;\n font-size: 10px;\n margin-top: 4px;\n}\n#dev-panel .dev-state {\n margin: 0;\n padding: 8px;\n background: #060a0e;\n border-radius: 8px;\n overflow: auto;\n max-height: 40vh;\n white-space: pre;\n color: #c8e6c9;\n}\n#dev-panel .dev-log {\n display: flex;\n flex-direction: column;\n gap: 2px;\n overflow-y: auto;\n max-height: 24vh;\n background: #060a0e;\n border-radius: 8px;\n padding: 6px 8px;\n}\n#dev-panel .dev-log-line { white-space: pre-wrap; word-break: break-word; line-height: 1.4; }\n#dev-panel .dev-log-invoke { color: #9ecbff; }\n#dev-panel .dev-log-result { color: #86efac; }\n#dev-panel .dev-log-error { color: #fca5a5; }\n`;\n"],"mappings":";AAgBA,IAAI;AACJ,IAAI;AACJ,IAAI,oBAAmC,EAAE;AAGzC,SAAS,cAAoB;AAC3B,KAAI,CAAC,QAAS;AACd,SAAQ,cAAc,KAAK,UAAU,YAAY,EAAE,MAAM,EAAE;;AAG7D,SAAS,QAAQ,MAAc,MAA2C;AACxE,KAAI,CAAC,MAAO;CACZ,MAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,MAAK,YAAY,wBAAwB;AAEzC,MAAK,cAAc,oBADN,IAAI,MAAM,EAAC,oBACF,CAAK,IAAI;AAC/B,OAAM,YAAY,KAAK;AACvB,OAAM,YAAY,MAAM;;AAG1B,IAAM,eAAe;AAErB,SAAS,aAAa,OAAoB,WAA0B;AAClE,OAAM,UAAU,OAAO,aAAa,UAAU;CAC9C,MAAM,SAAS,MAAM,cAAiC,cAAc;AACpE,KAAI,QAAQ;AACV,SAAO,cAAc,YAAY,MAAM;AACvC,SAAO,QAAQ,YAAY,qBAAqB;AAChD,SAAO,aAAa,iBAAiB,OAAO,CAAC,UAAU,CAAC;;AAE1D,KAAI;AACF,eAAa,QAAQ,cAAc,YAAY,MAAM,IAAI;SACnD;;AAKV,SAAgB,aAAa,SAAgC;CAC3D,MAAM,EAAE,OAAO,QAAQ,WAAW;AAClC,cAAa,MAAM;AACnB,eAAc;CACd,MAAM,OACJ,OAAO,WAAW,WACd,SAAS,cAAc,OAAO,GAC9B,kBAAkB,UAChB,SACA,SAAS;CACjB,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,OAAM,KAAK;AACX,EAAC,QAAQ,SAAS,MAAM,YAAY,MAAM;AAK1C,OAAM,YAAY;;;;;;;0DAHC,OAAO,0BAA0B,IAAI,EAAE,EAC/B,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,KAAK,IAAI,IASG;;;;;;;AAQ/D,WAAU,MAAM,cAA2B,aAAa;AACxD,SAAQ,MAAM,cAA2B,WAAW;AAErC,OAAM,cAAiC,cACtD,EAAQ,iBAAiB,UAAU,MAAM;AACvC,IAAE,iBAAiB;AACnB,eAAa,OAAO,CAAC,MAAM,UAAU,SAAS,YAAY,CAAC;GAC3D;AAEF,OAAM,iBAAiB,eAAe;AACpC,MAAI,MAAM,UAAU,SAAS,YAAY,CAAE,cAAa,OAAO,MAAM;GACrE;CAEF,IAAI,iBAAiB;AACrB,KAAI;AACF,mBAAiB,aAAa,QAAQ,aAAa,KAAK;SAClD;AAGR,cAAa,OAAO,eAAe;AAEnC,QAAO,GAAG,oBAAoB,EAAE,cAAc,WAAW,WAAW;AAClE,UAAQ,KAAK,aAAa,GAAG,KAAK,UAAU,QAAQ,EAAE,CAAC,CAAC,IAAI,SAAS;GACrE;AACF,QAAO,GAAG,oBAAoB,EAAE,QAAQ,YAAY;AAClD,UACE,QAAQ,YAAY,UAAU,KAAK,KAAK,UAAU,OAAO,IACzD,QAAQ,UAAU,SACnB;GACD;AAGF,OAAM,UAAU,YAAY;AAC5B,cAAa;;AAGf,IAAM,WAAW;AAEjB,SAAS,eAAqB;AAC5B,KAAI,SAAS,eAAe,SAAS,CAAE;CACvC,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,OAAM,KAAK;AACX,OAAM,cAAc;AACpB,UAAS,KAAK,YAAY,MAAM;;AAGlC,IAAM,YAAY"}
|