hypha-debugger 0.1.3 → 0.1.5
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/dist/debugger.d.ts +18 -6
- package/dist/hypha-debugger.js +435 -32
- package/dist/hypha-debugger.js.map +1 -1
- package/dist/hypha-debugger.min.js +2 -2
- package/dist/hypha-debugger.min.js.map +1 -1
- package/dist/hypha-debugger.mjs +408 -33
- package/dist/hypha-debugger.mjs.map +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/services/navigate.d.ts +11 -1
- package/dist/utils/wrap-fn.d.ts +13 -0
- package/package.json +1 -1
package/dist/hypha-debugger.mjs
CHANGED
|
@@ -742,6 +742,31 @@ getPageInfo.__schema__ = {
|
|
|
742
742
|
},
|
|
743
743
|
},
|
|
744
744
|
};
|
|
745
|
+
function getConsoleLogs(options) {
|
|
746
|
+
const logs = window.__HYPHA_DEBUGGER__?.consoleLogs ?? [];
|
|
747
|
+
const level = options?.level;
|
|
748
|
+
const limit = options?.limit ?? 100;
|
|
749
|
+
let filtered = level ? logs.filter((l) => l.level === level) : logs;
|
|
750
|
+
return filtered.slice(-limit);
|
|
751
|
+
}
|
|
752
|
+
getConsoleLogs.__schema__ = {
|
|
753
|
+
name: "getConsoleLogs",
|
|
754
|
+
description: "Retrieve captured console output (log, warn, error, info).",
|
|
755
|
+
parameters: {
|
|
756
|
+
type: "object",
|
|
757
|
+
properties: {
|
|
758
|
+
level: {
|
|
759
|
+
type: "string",
|
|
760
|
+
description: 'Filter by log level: "log", "warn", "error", "info". Omit for all levels.',
|
|
761
|
+
enum: ["log", "warn", "error", "info"],
|
|
762
|
+
},
|
|
763
|
+
limit: {
|
|
764
|
+
type: "number",
|
|
765
|
+
description: "Maximum number of log entries to return (most recent). Default: 100.",
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
};
|
|
745
770
|
/** Install console interceptor to capture logs. */
|
|
746
771
|
function installConsoleCapture(maxEntries = 500) {
|
|
747
772
|
var _a;
|
|
@@ -941,6 +966,88 @@ scrollTo.__schema__ = {
|
|
|
941
966
|
required: ["target"],
|
|
942
967
|
},
|
|
943
968
|
};
|
|
969
|
+
function getComputedStyles(selector, properties) {
|
|
970
|
+
const el = document.querySelector(selector);
|
|
971
|
+
if (!el) {
|
|
972
|
+
return { error: `No element found for selector: ${selector}` };
|
|
973
|
+
}
|
|
974
|
+
const computed = getComputedStyle(el);
|
|
975
|
+
const result = {};
|
|
976
|
+
const props = properties ??
|
|
977
|
+
[
|
|
978
|
+
"display",
|
|
979
|
+
"position",
|
|
980
|
+
"width",
|
|
981
|
+
"height",
|
|
982
|
+
"color",
|
|
983
|
+
"background-color",
|
|
984
|
+
"font-size",
|
|
985
|
+
"font-family",
|
|
986
|
+
"margin",
|
|
987
|
+
"padding",
|
|
988
|
+
"border",
|
|
989
|
+
"opacity",
|
|
990
|
+
"visibility",
|
|
991
|
+
"overflow",
|
|
992
|
+
"z-index",
|
|
993
|
+
];
|
|
994
|
+
for (const prop of props) {
|
|
995
|
+
result[prop] = computed.getPropertyValue(prop);
|
|
996
|
+
}
|
|
997
|
+
return result;
|
|
998
|
+
}
|
|
999
|
+
getComputedStyles.__schema__ = {
|
|
1000
|
+
name: "getComputedStyles",
|
|
1001
|
+
description: "Get computed CSS styles for an element.",
|
|
1002
|
+
parameters: {
|
|
1003
|
+
type: "object",
|
|
1004
|
+
properties: {
|
|
1005
|
+
selector: {
|
|
1006
|
+
type: "string",
|
|
1007
|
+
description: "CSS selector of the element.",
|
|
1008
|
+
},
|
|
1009
|
+
properties: {
|
|
1010
|
+
type: "array",
|
|
1011
|
+
items: { type: "string" },
|
|
1012
|
+
description: 'CSS property names to retrieve, e.g. ["color", "font-size"]. Omit for common defaults.',
|
|
1013
|
+
},
|
|
1014
|
+
},
|
|
1015
|
+
required: ["selector"],
|
|
1016
|
+
},
|
|
1017
|
+
};
|
|
1018
|
+
function getElementBounds(selector) {
|
|
1019
|
+
const el = document.querySelector(selector);
|
|
1020
|
+
if (!el) {
|
|
1021
|
+
return { error: `No element found for selector: ${selector}` };
|
|
1022
|
+
}
|
|
1023
|
+
const rect = el.getBoundingClientRect();
|
|
1024
|
+
return {
|
|
1025
|
+
bounds: {
|
|
1026
|
+
x: Math.round(rect.x),
|
|
1027
|
+
y: Math.round(rect.y),
|
|
1028
|
+
width: Math.round(rect.width),
|
|
1029
|
+
height: Math.round(rect.height),
|
|
1030
|
+
},
|
|
1031
|
+
visible: rect.width > 0 &&
|
|
1032
|
+
rect.height > 0 &&
|
|
1033
|
+
getComputedStyle(el).visibility !== "hidden" &&
|
|
1034
|
+
getComputedStyle(el).display !== "none",
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
getElementBounds.__schema__ = {
|
|
1038
|
+
name: "getElementBounds",
|
|
1039
|
+
description: "Get the bounding rectangle and visibility of a DOM element.",
|
|
1040
|
+
parameters: {
|
|
1041
|
+
type: "object",
|
|
1042
|
+
properties: {
|
|
1043
|
+
selector: {
|
|
1044
|
+
type: "string",
|
|
1045
|
+
description: "CSS selector of the element.",
|
|
1046
|
+
},
|
|
1047
|
+
},
|
|
1048
|
+
required: ["selector"],
|
|
1049
|
+
},
|
|
1050
|
+
};
|
|
944
1051
|
function getHtml(selector, outer, max_length) {
|
|
945
1052
|
const useOuter = outer ?? true;
|
|
946
1053
|
const maxLen = max_length ?? 50000;
|
|
@@ -2020,20 +2127,123 @@ executeScript.__schema__ = {
|
|
|
2020
2127
|
};
|
|
2021
2128
|
|
|
2022
2129
|
/**
|
|
2023
|
-
* Navigation service.
|
|
2130
|
+
* Navigation service with auto-reconnect support.
|
|
2131
|
+
*
|
|
2132
|
+
* For agent-triggered reload() and same-origin navigate(), we use a "soft"
|
|
2133
|
+
* approach: fetch the target HTML, inject the debugger <script> tag, then
|
|
2134
|
+
* replace the document via document.write(). The injected script auto-starts
|
|
2135
|
+
* from sessionStorage config, so the debugger reconnects with the same
|
|
2136
|
+
* workspace and service ID. The agent's URL stays stable.
|
|
2137
|
+
*
|
|
2138
|
+
* For cross-origin navigate(), goBack(), and goForward(), we fall back to
|
|
2139
|
+
* normal navigation. The debugger config is saved to sessionStorage so
|
|
2140
|
+
* re-clicking the bookmarklet reconnects seamlessly.
|
|
2141
|
+
*/
|
|
2142
|
+
const STORAGE_KEY$1 = "__hypha_debugger_config__";
|
|
2143
|
+
/** Read the saved script URL from sessionStorage, or fall back to CDN. */
|
|
2144
|
+
function getScriptUrl() {
|
|
2145
|
+
try {
|
|
2146
|
+
const raw = sessionStorage.getItem(STORAGE_KEY$1);
|
|
2147
|
+
if (raw) {
|
|
2148
|
+
const config = JSON.parse(raw);
|
|
2149
|
+
if (config.script_url)
|
|
2150
|
+
return config.script_url;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
catch {
|
|
2154
|
+
// ignore
|
|
2155
|
+
}
|
|
2156
|
+
return "https://cdn.jsdelivr.net/npm/hypha-debugger/dist/hypha-debugger.min.js";
|
|
2157
|
+
}
|
|
2158
|
+
/**
|
|
2159
|
+
* Inject the debugger loader script into HTML before </body> (or append).
|
|
2160
|
+
* Also injects a tiny inline script that reads sessionStorage and passes
|
|
2161
|
+
* config to the debugger via a global, so autoStart() picks it up.
|
|
2024
2162
|
*/
|
|
2163
|
+
function injectLoader(html, scriptUrl) {
|
|
2164
|
+
const loader = `<script src="${scriptUrl}"><\/script>`;
|
|
2165
|
+
if (html.includes("</body>")) {
|
|
2166
|
+
return html.replace("</body>", loader + "\n</body>");
|
|
2167
|
+
}
|
|
2168
|
+
if (html.includes("</html>")) {
|
|
2169
|
+
return html.replace("</html>", loader + "\n</html>");
|
|
2170
|
+
}
|
|
2171
|
+
return html + "\n" + loader;
|
|
2172
|
+
}
|
|
2173
|
+
/**
|
|
2174
|
+
* Perform a soft page replacement: fetch HTML, inject debugger script,
|
|
2175
|
+
* replace the document. Returns false if it can't be done (caller should
|
|
2176
|
+
* fall back to hard navigation).
|
|
2177
|
+
*/
|
|
2178
|
+
function softReplace(url, pushState) {
|
|
2179
|
+
const scriptUrl = getScriptUrl();
|
|
2180
|
+
fetch(url, { credentials: "same-origin", cache: "reload" })
|
|
2181
|
+
.then((response) => {
|
|
2182
|
+
if (!response.ok)
|
|
2183
|
+
throw new Error(`HTTP ${response.status}`);
|
|
2184
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
2185
|
+
if (!contentType.includes("text/html")) {
|
|
2186
|
+
throw new Error("Not HTML");
|
|
2187
|
+
}
|
|
2188
|
+
return response.text();
|
|
2189
|
+
})
|
|
2190
|
+
.then((html) => {
|
|
2191
|
+
const modified = injectLoader(html, scriptUrl);
|
|
2192
|
+
document.open();
|
|
2193
|
+
document.write(modified);
|
|
2194
|
+
document.close();
|
|
2195
|
+
if (pushState) {
|
|
2196
|
+
try {
|
|
2197
|
+
history.pushState({}, "", pushState);
|
|
2198
|
+
}
|
|
2199
|
+
catch {
|
|
2200
|
+
// ignore — URL might already match
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
})
|
|
2204
|
+
.catch(() => {
|
|
2205
|
+
// Soft replace failed — fall back to hard navigation
|
|
2206
|
+
if (pushState) {
|
|
2207
|
+
window.location.href = pushState;
|
|
2208
|
+
}
|
|
2209
|
+
else {
|
|
2210
|
+
window.location.reload();
|
|
2211
|
+
}
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
// ── navigate ──────────────────────────────────────────────────────────
|
|
2025
2215
|
function navigate(url) {
|
|
2026
2216
|
try {
|
|
2027
|
-
|
|
2028
|
-
|
|
2217
|
+
const targetUrl = new URL(url, location.href);
|
|
2218
|
+
const sameOrigin = targetUrl.origin === location.origin;
|
|
2219
|
+
if (sameOrigin) {
|
|
2220
|
+
// Soft navigate: fetch + inject + document.write, then pushState
|
|
2221
|
+
// Schedule after RPC response is sent
|
|
2222
|
+
setTimeout(() => softReplace(targetUrl.href, targetUrl.href), 150);
|
|
2223
|
+
return {
|
|
2224
|
+
success: true,
|
|
2225
|
+
message: `Navigating to ${url} (debugger will auto-reconnect)`,
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
else {
|
|
2229
|
+
// Cross-origin: can't soft navigate, fall back to hard
|
|
2230
|
+
window.location.href = url;
|
|
2231
|
+
return {
|
|
2232
|
+
success: true,
|
|
2233
|
+
message: `Navigating to ${url} (cross-origin, debugger will disconnect)`,
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2029
2236
|
}
|
|
2030
2237
|
catch (err) {
|
|
2031
|
-
return {
|
|
2238
|
+
return {
|
|
2239
|
+
success: false,
|
|
2240
|
+
message: `Navigation failed: ${err.message ?? err}`,
|
|
2241
|
+
};
|
|
2032
2242
|
}
|
|
2033
2243
|
}
|
|
2034
2244
|
navigate.__schema__ = {
|
|
2035
2245
|
name: "navigate",
|
|
2036
|
-
description: "Navigate the browser to a new URL.",
|
|
2246
|
+
description: "Navigate the browser to a new URL. For same-origin URLs, the debugger auto-reconnects. Cross-origin navigation will disconnect the debugger.",
|
|
2037
2247
|
parameters: {
|
|
2038
2248
|
type: "object",
|
|
2039
2249
|
properties: {
|
|
@@ -2045,6 +2255,75 @@ navigate.__schema__ = {
|
|
|
2045
2255
|
required: ["url"],
|
|
2046
2256
|
},
|
|
2047
2257
|
};
|
|
2258
|
+
// ── goBack / goForward ───────────────────────────────────────────────
|
|
2259
|
+
function goBack() {
|
|
2260
|
+
try {
|
|
2261
|
+
window.history.back();
|
|
2262
|
+
return {
|
|
2263
|
+
success: true,
|
|
2264
|
+
message: "Navigated back (re-click bookmarklet to reconnect if needed)",
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
catch (err) {
|
|
2268
|
+
return {
|
|
2269
|
+
success: false,
|
|
2270
|
+
message: `Back navigation failed: ${err.message ?? err}`,
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
goBack.__schema__ = {
|
|
2275
|
+
name: "goBack",
|
|
2276
|
+
description: "Navigate back in browser history. The debugger may disconnect — re-click the bookmarklet to reconnect.",
|
|
2277
|
+
parameters: {
|
|
2278
|
+
type: "object",
|
|
2279
|
+
properties: {},
|
|
2280
|
+
},
|
|
2281
|
+
};
|
|
2282
|
+
function goForward() {
|
|
2283
|
+
try {
|
|
2284
|
+
window.history.forward();
|
|
2285
|
+
return {
|
|
2286
|
+
success: true,
|
|
2287
|
+
message: "Navigated forward (re-click bookmarklet to reconnect if needed)",
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
catch (err) {
|
|
2291
|
+
return {
|
|
2292
|
+
success: false,
|
|
2293
|
+
message: `Forward navigation failed: ${err.message ?? err}`,
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
goForward.__schema__ = {
|
|
2298
|
+
name: "goForward",
|
|
2299
|
+
description: "Navigate forward in browser history. The debugger may disconnect — re-click the bookmarklet to reconnect.",
|
|
2300
|
+
parameters: {
|
|
2301
|
+
type: "object",
|
|
2302
|
+
properties: {},
|
|
2303
|
+
},
|
|
2304
|
+
};
|
|
2305
|
+
// ── reload ───────────────────────────────────────────────────────────
|
|
2306
|
+
function reload() {
|
|
2307
|
+
try {
|
|
2308
|
+
// Schedule soft reload after RPC response is sent
|
|
2309
|
+
setTimeout(() => softReplace(location.href), 150);
|
|
2310
|
+
return {
|
|
2311
|
+
success: true,
|
|
2312
|
+
message: "Reloading page (debugger will auto-reconnect)",
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
catch (err) {
|
|
2316
|
+
return { success: false, message: `Reload failed: ${err.message ?? err}` };
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
reload.__schema__ = {
|
|
2320
|
+
name: "reload",
|
|
2321
|
+
description: "Reload the current page. The debugger auto-reconnects after reload using soft page replacement.",
|
|
2322
|
+
parameters: {
|
|
2323
|
+
type: "object",
|
|
2324
|
+
properties: {},
|
|
2325
|
+
},
|
|
2326
|
+
};
|
|
2048
2327
|
|
|
2049
2328
|
/**
|
|
2050
2329
|
* React component tree inspection service.
|
|
@@ -2387,6 +2666,33 @@ function generateSkillMd(serviceFunctions, serviceUrl) {
|
|
|
2387
2666
|
return [frontmatter, intro, functionDocs.join("\n"), tips].join("\n");
|
|
2388
2667
|
}
|
|
2389
2668
|
|
|
2669
|
+
/**
|
|
2670
|
+
* Wrap a function with correct, unminified parameter names for hypha-rpc.
|
|
2671
|
+
*
|
|
2672
|
+
* In production builds, Babel/Terser minifies parameter names (e.g. 'code' → 'e').
|
|
2673
|
+
* hypha-rpc's getParamNames() parses Function.toString() to map kwargs to
|
|
2674
|
+
* positional args. With minified names, kwargs like {code: '...'} can't be
|
|
2675
|
+
* mapped and args are silently dropped.
|
|
2676
|
+
*
|
|
2677
|
+
* This helper uses new Function() to create a wrapper whose parameter names
|
|
2678
|
+
* are taken from the function's __schema__ property, so hypha-rpc always sees
|
|
2679
|
+
* the real parameter names regardless of minification.
|
|
2680
|
+
*/
|
|
2681
|
+
function wrapFn(fn) {
|
|
2682
|
+
const schema = fn.__schema__;
|
|
2683
|
+
const paramNames = schema?.parameters?.properties
|
|
2684
|
+
? Object.keys(schema.parameters.properties)
|
|
2685
|
+
: [];
|
|
2686
|
+
if (paramNames.length === 0) {
|
|
2687
|
+
return fn;
|
|
2688
|
+
}
|
|
2689
|
+
const paramList = paramNames.join(", ");
|
|
2690
|
+
const wrapper = new Function("fn", `return async function(${paramList}) { return fn(${paramList}); }`)(fn);
|
|
2691
|
+
if (schema)
|
|
2692
|
+
wrapper.__schema__ = schema;
|
|
2693
|
+
return wrapper;
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2390
2696
|
/**
|
|
2391
2697
|
* @file port from browser-use
|
|
2392
2698
|
* @see https://github.com/browser-use/browser-use/commits/main/browser_use/dom/dom_tree/index.js
|
|
@@ -5123,12 +5429,15 @@ function randomHex(bytes = 8) {
|
|
|
5123
5429
|
crypto.getRandomValues(arr);
|
|
5124
5430
|
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
5125
5431
|
}
|
|
5432
|
+
/** sessionStorage key for persisting debugger config across reloads. */
|
|
5433
|
+
const STORAGE_KEY = "__hypha_debugger_config__";
|
|
5126
5434
|
class HyphaDebugger {
|
|
5127
5435
|
constructor(config) {
|
|
5128
5436
|
this.overlay = null;
|
|
5129
5437
|
this.cursor = null;
|
|
5130
5438
|
this.server = null;
|
|
5131
5439
|
this.serviceInfo = null;
|
|
5440
|
+
this.boundBeforeUnload = null;
|
|
5132
5441
|
const requireToken = config.require_token ?? false;
|
|
5133
5442
|
// Always append random suffix unless user provided a custom id.
|
|
5134
5443
|
let serviceId = config.service_id ?? "web-debugger";
|
|
@@ -5188,6 +5497,10 @@ class HyphaDebugger {
|
|
|
5188
5497
|
// Store globally
|
|
5189
5498
|
w.__HYPHA_DEBUGGER__ = w.__HYPHA_DEBUGGER__ ?? {};
|
|
5190
5499
|
w.__HYPHA_DEBUGGER__.instance = this;
|
|
5500
|
+
// Persist config to sessionStorage for auto-reconnect after reload
|
|
5501
|
+
this.saveConfigToStorage();
|
|
5502
|
+
this.boundBeforeUnload = () => this.saveConfigToStorage();
|
|
5503
|
+
window.addEventListener("beforeunload", this.boundBeforeUnload);
|
|
5191
5504
|
return session;
|
|
5192
5505
|
}
|
|
5193
5506
|
catch (err) {
|
|
@@ -5203,6 +5516,11 @@ class HyphaDebugger {
|
|
|
5203
5516
|
}
|
|
5204
5517
|
}
|
|
5205
5518
|
async destroy() {
|
|
5519
|
+
// Remove beforeunload listener
|
|
5520
|
+
if (this.boundBeforeUnload) {
|
|
5521
|
+
window.removeEventListener("beforeunload", this.boundBeforeUnload);
|
|
5522
|
+
this.boundBeforeUnload = null;
|
|
5523
|
+
}
|
|
5206
5524
|
try {
|
|
5207
5525
|
if (this.serviceInfo && this.server) {
|
|
5208
5526
|
await this.server.unregisterService(this.serviceInfo.id);
|
|
@@ -5211,6 +5529,13 @@ class HyphaDebugger {
|
|
|
5211
5529
|
catch {
|
|
5212
5530
|
// Ignore unregister errors on cleanup
|
|
5213
5531
|
}
|
|
5532
|
+
// Clear sessionStorage config (explicit destroy = user wants to stop)
|
|
5533
|
+
try {
|
|
5534
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
5535
|
+
}
|
|
5536
|
+
catch {
|
|
5537
|
+
// ignore
|
|
5538
|
+
}
|
|
5214
5539
|
disposeController();
|
|
5215
5540
|
this.cursor?.destroy();
|
|
5216
5541
|
this.cursor = null;
|
|
@@ -5222,6 +5547,48 @@ class HyphaDebugger {
|
|
|
5222
5547
|
delete w.__HYPHA_DEBUGGER__.session;
|
|
5223
5548
|
}
|
|
5224
5549
|
}
|
|
5550
|
+
/**
|
|
5551
|
+
* Persist debugger config to sessionStorage so the debugger can
|
|
5552
|
+
* auto-reconnect after a page reload (soft reload injects the script,
|
|
5553
|
+
* autoStart() reads this config).
|
|
5554
|
+
*/
|
|
5555
|
+
saveConfigToStorage() {
|
|
5556
|
+
try {
|
|
5557
|
+
const data = {
|
|
5558
|
+
server_url: this.config.server_url,
|
|
5559
|
+
workspace: this.server?.config?.workspace ?? this.config.workspace,
|
|
5560
|
+
token: this.config.token,
|
|
5561
|
+
service_id: this.config.service_id,
|
|
5562
|
+
service_name: this.config.service_name,
|
|
5563
|
+
show_ui: this.config.show_ui,
|
|
5564
|
+
visibility: this.config.visibility,
|
|
5565
|
+
require_token: this.config.require_token,
|
|
5566
|
+
script_url: this.detectScriptUrl(),
|
|
5567
|
+
};
|
|
5568
|
+
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
5569
|
+
}
|
|
5570
|
+
catch {
|
|
5571
|
+
// sessionStorage might be unavailable (private browsing, full quota)
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
/**
|
|
5575
|
+
* Detect the URL of the currently loaded hypha-debugger script.
|
|
5576
|
+
* Used by navigate.ts to inject the correct script after soft reload.
|
|
5577
|
+
*/
|
|
5578
|
+
detectScriptUrl() {
|
|
5579
|
+
try {
|
|
5580
|
+
const scripts = document.querySelectorAll("script[src]");
|
|
5581
|
+
for (const s of Array.from(scripts)) {
|
|
5582
|
+
if (s.src && s.src.includes("hypha-debugger")) {
|
|
5583
|
+
return s.src;
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
}
|
|
5587
|
+
catch {
|
|
5588
|
+
// ignore
|
|
5589
|
+
}
|
|
5590
|
+
return "https://cdn.jsdelivr.net/npm/hypha-debugger/dist/hypha-debugger.min.js";
|
|
5591
|
+
}
|
|
5225
5592
|
/**
|
|
5226
5593
|
* Generate token, build service URL, update overlay instructions, and
|
|
5227
5594
|
* return a DebugSession.
|
|
@@ -5391,21 +5758,17 @@ class HyphaDebugger {
|
|
|
5391
5758
|
return lines.join("\n");
|
|
5392
5759
|
}
|
|
5393
5760
|
/**
|
|
5394
|
-
* Wrap a service function with logging
|
|
5761
|
+
* Wrap a service function with overlay logging + correct parameter names.
|
|
5395
5762
|
*
|
|
5396
|
-
*
|
|
5397
|
-
*
|
|
5398
|
-
*
|
|
5399
|
-
*
|
|
5400
|
-
*
|
|
5763
|
+
* Adds logging around the function, then applies baseWrapFn() which uses
|
|
5764
|
+
* new Function() to create a wrapper with unminified parameter names from
|
|
5765
|
+
* __schema__. This is critical for production builds where Babel/Terser
|
|
5766
|
+
* minifies parameter names — hypha-rpc's getParamNames() parses
|
|
5767
|
+
* Function.toString() to map kwargs to positional args.
|
|
5401
5768
|
*/
|
|
5402
5769
|
wrapFn(fn, name) {
|
|
5403
|
-
const schema = fn.__schema__;
|
|
5404
|
-
const paramNames = schema?.parameters?.properties
|
|
5405
|
-
? Object.keys(schema.parameters.properties)
|
|
5406
|
-
: [];
|
|
5407
5770
|
const self = this;
|
|
5408
|
-
const
|
|
5771
|
+
const logged = async (...args) => {
|
|
5409
5772
|
self.overlay?.addLog(`${name}(${self.summarizeArgs(args)})`, "call");
|
|
5410
5773
|
try {
|
|
5411
5774
|
const result = await fn(...args);
|
|
@@ -5423,19 +5786,10 @@ class HyphaDebugger {
|
|
|
5423
5786
|
throw err;
|
|
5424
5787
|
}
|
|
5425
5788
|
};
|
|
5426
|
-
|
|
5427
|
-
if (
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
else {
|
|
5431
|
-
// Create a function with explicit, unminified parameter names so
|
|
5432
|
-
// hypha-rpc can parse them from Function.toString().
|
|
5433
|
-
const paramList = paramNames.join(", ");
|
|
5434
|
-
wrapper = new Function("callAndLog", `return async function(${paramList}) { return callAndLog([${paramList}]); }`)(callAndLog);
|
|
5435
|
-
}
|
|
5436
|
-
if (schema)
|
|
5437
|
-
wrapper.__schema__ = schema;
|
|
5438
|
-
return wrapper;
|
|
5789
|
+
// Preserve __schema__ so baseWrapFn can read parameter names
|
|
5790
|
+
if (fn.__schema__)
|
|
5791
|
+
logged.__schema__ = fn.__schema__;
|
|
5792
|
+
return wrapFn(logged);
|
|
5439
5793
|
}
|
|
5440
5794
|
summarizeArgs(args) {
|
|
5441
5795
|
if (args.length === 0)
|
|
@@ -5465,7 +5819,11 @@ class HyphaDebugger {
|
|
|
5465
5819
|
* Programmatic usage:
|
|
5466
5820
|
* import { startDebugger } from 'hypha-debugger';
|
|
5467
5821
|
* const session = await startDebugger({ server_url: 'https://hypha.aicell.io' });
|
|
5822
|
+
*
|
|
5823
|
+
* Library usage (import individual functions):
|
|
5824
|
+
* import { getPageInfo, clickElement, wrapFn, PageController } from 'hypha-debugger';
|
|
5468
5825
|
*/
|
|
5826
|
+
// ── Core debugger ──
|
|
5469
5827
|
/**
|
|
5470
5828
|
* Start the Hypha debugger. Connects to a Hypha server and registers
|
|
5471
5829
|
* a debug service that remote clients can use to inspect and interact
|
|
@@ -5486,6 +5844,26 @@ async function startDebugger(config) {
|
|
|
5486
5844
|
function autoStart() {
|
|
5487
5845
|
if (typeof window === "undefined" || typeof document === "undefined")
|
|
5488
5846
|
return;
|
|
5847
|
+
// Skip if already started
|
|
5848
|
+
if (window.__HYPHA_DEBUGGER__?.instance)
|
|
5849
|
+
return;
|
|
5850
|
+
// Check sessionStorage for saved config (auto-reconnect after soft reload)
|
|
5851
|
+
try {
|
|
5852
|
+
const saved = sessionStorage.getItem("__hypha_debugger_config__");
|
|
5853
|
+
if (saved) {
|
|
5854
|
+
const savedConfig = JSON.parse(saved);
|
|
5855
|
+
if (savedConfig.server_url) {
|
|
5856
|
+
console.log("[hypha-debugger] Reconnecting from saved session...");
|
|
5857
|
+
startDebugger(savedConfig).catch((err) => {
|
|
5858
|
+
console.error("[hypha-debugger] Auto-reconnect failed:", err);
|
|
5859
|
+
});
|
|
5860
|
+
return;
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
}
|
|
5864
|
+
catch {
|
|
5865
|
+
// sessionStorage not available or parse error — continue to script tag detection
|
|
5866
|
+
}
|
|
5489
5867
|
// Find our own script tag
|
|
5490
5868
|
const scripts = document.querySelectorAll("script[src]");
|
|
5491
5869
|
let scriptEl = null;
|
|
@@ -5498,9 +5876,6 @@ function autoStart() {
|
|
|
5498
5876
|
// Skip if data-manual is set
|
|
5499
5877
|
if (scriptEl?.hasAttribute("data-manual"))
|
|
5500
5878
|
return;
|
|
5501
|
-
// Skip if already started
|
|
5502
|
-
if (window.__HYPHA_DEBUGGER__?.instance)
|
|
5503
|
-
return;
|
|
5504
5879
|
const serverUrl = scriptEl?.getAttribute("data-server-url") ?? "https://hypha.aicell.io";
|
|
5505
5880
|
const config = {
|
|
5506
5881
|
server_url: serverUrl,
|
|
@@ -5534,5 +5909,5 @@ if (typeof window !== "undefined") {
|
|
|
5534
5909
|
}
|
|
5535
5910
|
}
|
|
5536
5911
|
|
|
5537
|
-
export { HyphaDebugger, startDebugger };
|
|
5912
|
+
export { AICursor, HyphaDebugger, PageController, clickElement$1 as clickElement, clickElementByIndex, disposeController, executeScript, fillInput, generateSkillMd, getBrowserState, getComputedStyles, getConsoleLogs, getElementBounds, getHtml, getPageInfo, getReactTree, goBack, goForward, inputText, installConsoleCapture, navigate, queryDom, reload, removeHighlights, scroll, scrollTo, selectOption, startDebugger, takeScreenshot, wrapFn };
|
|
5538
5913
|
//# sourceMappingURL=hypha-debugger.mjs.map
|