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/debugger.d.ts
CHANGED
|
@@ -45,9 +45,21 @@ export declare class HyphaDebugger {
|
|
|
45
45
|
private cursor;
|
|
46
46
|
private server;
|
|
47
47
|
private serviceInfo;
|
|
48
|
+
private boundBeforeUnload;
|
|
48
49
|
constructor(config: DebuggerConfig);
|
|
49
50
|
start(): Promise<DebugSession>;
|
|
50
51
|
destroy(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Persist debugger config to sessionStorage so the debugger can
|
|
54
|
+
* auto-reconnect after a page reload (soft reload injects the script,
|
|
55
|
+
* autoStart() reads this config).
|
|
56
|
+
*/
|
|
57
|
+
private saveConfigToStorage;
|
|
58
|
+
/**
|
|
59
|
+
* Detect the URL of the currently loaded hypha-debugger script.
|
|
60
|
+
* Used by navigate.ts to inject the correct script after soft reload.
|
|
61
|
+
*/
|
|
62
|
+
private detectScriptUrl;
|
|
51
63
|
/**
|
|
52
64
|
* Generate token, build service URL, update overlay instructions, and
|
|
53
65
|
* return a DebugSession.
|
|
@@ -66,13 +78,13 @@ export declare class HyphaDebugger {
|
|
|
66
78
|
/** Build the instruction block for the overlay panel. */
|
|
67
79
|
private buildInstructionBlock;
|
|
68
80
|
/**
|
|
69
|
-
* Wrap a service function with logging
|
|
81
|
+
* Wrap a service function with overlay logging + correct parameter names.
|
|
70
82
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
83
|
+
* Adds logging around the function, then applies baseWrapFn() which uses
|
|
84
|
+
* new Function() to create a wrapper with unminified parameter names from
|
|
85
|
+
* __schema__. This is critical for production builds where Babel/Terser
|
|
86
|
+
* minifies parameter names — hypha-rpc's getParamNames() parses
|
|
87
|
+
* Function.toString() to map kwargs to positional args.
|
|
76
88
|
*/
|
|
77
89
|
private wrapFn;
|
|
78
90
|
private summarizeArgs;
|
package/dist/hypha-debugger.js
CHANGED
|
@@ -9199,6 +9199,31 @@
|
|
|
9199
9199
|
},
|
|
9200
9200
|
},
|
|
9201
9201
|
};
|
|
9202
|
+
function getConsoleLogs(options) {
|
|
9203
|
+
const logs = window.__HYPHA_DEBUGGER__?.consoleLogs ?? [];
|
|
9204
|
+
const level = options?.level;
|
|
9205
|
+
const limit = options?.limit ?? 100;
|
|
9206
|
+
let filtered = level ? logs.filter((l) => l.level === level) : logs;
|
|
9207
|
+
return filtered.slice(-limit);
|
|
9208
|
+
}
|
|
9209
|
+
getConsoleLogs.__schema__ = {
|
|
9210
|
+
name: "getConsoleLogs",
|
|
9211
|
+
description: "Retrieve captured console output (log, warn, error, info).",
|
|
9212
|
+
parameters: {
|
|
9213
|
+
type: "object",
|
|
9214
|
+
properties: {
|
|
9215
|
+
level: {
|
|
9216
|
+
type: "string",
|
|
9217
|
+
description: 'Filter by log level: "log", "warn", "error", "info". Omit for all levels.',
|
|
9218
|
+
enum: ["log", "warn", "error", "info"],
|
|
9219
|
+
},
|
|
9220
|
+
limit: {
|
|
9221
|
+
type: "number",
|
|
9222
|
+
description: "Maximum number of log entries to return (most recent). Default: 100.",
|
|
9223
|
+
},
|
|
9224
|
+
},
|
|
9225
|
+
},
|
|
9226
|
+
};
|
|
9202
9227
|
/** Install console interceptor to capture logs. */
|
|
9203
9228
|
function installConsoleCapture(maxEntries = 500) {
|
|
9204
9229
|
var _a;
|
|
@@ -9398,6 +9423,88 @@
|
|
|
9398
9423
|
required: ["target"],
|
|
9399
9424
|
},
|
|
9400
9425
|
};
|
|
9426
|
+
function getComputedStyles(selector, properties) {
|
|
9427
|
+
const el = document.querySelector(selector);
|
|
9428
|
+
if (!el) {
|
|
9429
|
+
return { error: `No element found for selector: ${selector}` };
|
|
9430
|
+
}
|
|
9431
|
+
const computed = getComputedStyle(el);
|
|
9432
|
+
const result = {};
|
|
9433
|
+
const props = properties ??
|
|
9434
|
+
[
|
|
9435
|
+
"display",
|
|
9436
|
+
"position",
|
|
9437
|
+
"width",
|
|
9438
|
+
"height",
|
|
9439
|
+
"color",
|
|
9440
|
+
"background-color",
|
|
9441
|
+
"font-size",
|
|
9442
|
+
"font-family",
|
|
9443
|
+
"margin",
|
|
9444
|
+
"padding",
|
|
9445
|
+
"border",
|
|
9446
|
+
"opacity",
|
|
9447
|
+
"visibility",
|
|
9448
|
+
"overflow",
|
|
9449
|
+
"z-index",
|
|
9450
|
+
];
|
|
9451
|
+
for (const prop of props) {
|
|
9452
|
+
result[prop] = computed.getPropertyValue(prop);
|
|
9453
|
+
}
|
|
9454
|
+
return result;
|
|
9455
|
+
}
|
|
9456
|
+
getComputedStyles.__schema__ = {
|
|
9457
|
+
name: "getComputedStyles",
|
|
9458
|
+
description: "Get computed CSS styles for an element.",
|
|
9459
|
+
parameters: {
|
|
9460
|
+
type: "object",
|
|
9461
|
+
properties: {
|
|
9462
|
+
selector: {
|
|
9463
|
+
type: "string",
|
|
9464
|
+
description: "CSS selector of the element.",
|
|
9465
|
+
},
|
|
9466
|
+
properties: {
|
|
9467
|
+
type: "array",
|
|
9468
|
+
items: { type: "string" },
|
|
9469
|
+
description: 'CSS property names to retrieve, e.g. ["color", "font-size"]. Omit for common defaults.',
|
|
9470
|
+
},
|
|
9471
|
+
},
|
|
9472
|
+
required: ["selector"],
|
|
9473
|
+
},
|
|
9474
|
+
};
|
|
9475
|
+
function getElementBounds(selector) {
|
|
9476
|
+
const el = document.querySelector(selector);
|
|
9477
|
+
if (!el) {
|
|
9478
|
+
return { error: `No element found for selector: ${selector}` };
|
|
9479
|
+
}
|
|
9480
|
+
const rect = el.getBoundingClientRect();
|
|
9481
|
+
return {
|
|
9482
|
+
bounds: {
|
|
9483
|
+
x: Math.round(rect.x),
|
|
9484
|
+
y: Math.round(rect.y),
|
|
9485
|
+
width: Math.round(rect.width),
|
|
9486
|
+
height: Math.round(rect.height),
|
|
9487
|
+
},
|
|
9488
|
+
visible: rect.width > 0 &&
|
|
9489
|
+
rect.height > 0 &&
|
|
9490
|
+
getComputedStyle(el).visibility !== "hidden" &&
|
|
9491
|
+
getComputedStyle(el).display !== "none",
|
|
9492
|
+
};
|
|
9493
|
+
}
|
|
9494
|
+
getElementBounds.__schema__ = {
|
|
9495
|
+
name: "getElementBounds",
|
|
9496
|
+
description: "Get the bounding rectangle and visibility of a DOM element.",
|
|
9497
|
+
parameters: {
|
|
9498
|
+
type: "object",
|
|
9499
|
+
properties: {
|
|
9500
|
+
selector: {
|
|
9501
|
+
type: "string",
|
|
9502
|
+
description: "CSS selector of the element.",
|
|
9503
|
+
},
|
|
9504
|
+
},
|
|
9505
|
+
required: ["selector"],
|
|
9506
|
+
},
|
|
9507
|
+
};
|
|
9401
9508
|
function getHtml(selector, outer, max_length) {
|
|
9402
9509
|
const useOuter = outer ?? true;
|
|
9403
9510
|
const maxLen = max_length ?? 50000;
|
|
@@ -10477,20 +10584,123 @@
|
|
|
10477
10584
|
};
|
|
10478
10585
|
|
|
10479
10586
|
/**
|
|
10480
|
-
* Navigation service.
|
|
10587
|
+
* Navigation service with auto-reconnect support.
|
|
10588
|
+
*
|
|
10589
|
+
* For agent-triggered reload() and same-origin navigate(), we use a "soft"
|
|
10590
|
+
* approach: fetch the target HTML, inject the debugger <script> tag, then
|
|
10591
|
+
* replace the document via document.write(). The injected script auto-starts
|
|
10592
|
+
* from sessionStorage config, so the debugger reconnects with the same
|
|
10593
|
+
* workspace and service ID. The agent's URL stays stable.
|
|
10594
|
+
*
|
|
10595
|
+
* For cross-origin navigate(), goBack(), and goForward(), we fall back to
|
|
10596
|
+
* normal navigation. The debugger config is saved to sessionStorage so
|
|
10597
|
+
* re-clicking the bookmarklet reconnects seamlessly.
|
|
10598
|
+
*/
|
|
10599
|
+
const STORAGE_KEY$1 = "__hypha_debugger_config__";
|
|
10600
|
+
/** Read the saved script URL from sessionStorage, or fall back to CDN. */
|
|
10601
|
+
function getScriptUrl() {
|
|
10602
|
+
try {
|
|
10603
|
+
const raw = sessionStorage.getItem(STORAGE_KEY$1);
|
|
10604
|
+
if (raw) {
|
|
10605
|
+
const config = JSON.parse(raw);
|
|
10606
|
+
if (config.script_url)
|
|
10607
|
+
return config.script_url;
|
|
10608
|
+
}
|
|
10609
|
+
}
|
|
10610
|
+
catch {
|
|
10611
|
+
// ignore
|
|
10612
|
+
}
|
|
10613
|
+
return "https://cdn.jsdelivr.net/npm/hypha-debugger/dist/hypha-debugger.min.js";
|
|
10614
|
+
}
|
|
10615
|
+
/**
|
|
10616
|
+
* Inject the debugger loader script into HTML before </body> (or append).
|
|
10617
|
+
* Also injects a tiny inline script that reads sessionStorage and passes
|
|
10618
|
+
* config to the debugger via a global, so autoStart() picks it up.
|
|
10619
|
+
*/
|
|
10620
|
+
function injectLoader(html, scriptUrl) {
|
|
10621
|
+
const loader = `<script src="${scriptUrl}"><\/script>`;
|
|
10622
|
+
if (html.includes("</body>")) {
|
|
10623
|
+
return html.replace("</body>", loader + "\n</body>");
|
|
10624
|
+
}
|
|
10625
|
+
if (html.includes("</html>")) {
|
|
10626
|
+
return html.replace("</html>", loader + "\n</html>");
|
|
10627
|
+
}
|
|
10628
|
+
return html + "\n" + loader;
|
|
10629
|
+
}
|
|
10630
|
+
/**
|
|
10631
|
+
* Perform a soft page replacement: fetch HTML, inject debugger script,
|
|
10632
|
+
* replace the document. Returns false if it can't be done (caller should
|
|
10633
|
+
* fall back to hard navigation).
|
|
10481
10634
|
*/
|
|
10635
|
+
function softReplace(url, pushState) {
|
|
10636
|
+
const scriptUrl = getScriptUrl();
|
|
10637
|
+
fetch(url, { credentials: "same-origin", cache: "reload" })
|
|
10638
|
+
.then((response) => {
|
|
10639
|
+
if (!response.ok)
|
|
10640
|
+
throw new Error(`HTTP ${response.status}`);
|
|
10641
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
10642
|
+
if (!contentType.includes("text/html")) {
|
|
10643
|
+
throw new Error("Not HTML");
|
|
10644
|
+
}
|
|
10645
|
+
return response.text();
|
|
10646
|
+
})
|
|
10647
|
+
.then((html) => {
|
|
10648
|
+
const modified = injectLoader(html, scriptUrl);
|
|
10649
|
+
document.open();
|
|
10650
|
+
document.write(modified);
|
|
10651
|
+
document.close();
|
|
10652
|
+
if (pushState) {
|
|
10653
|
+
try {
|
|
10654
|
+
history.pushState({}, "", pushState);
|
|
10655
|
+
}
|
|
10656
|
+
catch {
|
|
10657
|
+
// ignore — URL might already match
|
|
10658
|
+
}
|
|
10659
|
+
}
|
|
10660
|
+
})
|
|
10661
|
+
.catch(() => {
|
|
10662
|
+
// Soft replace failed — fall back to hard navigation
|
|
10663
|
+
if (pushState) {
|
|
10664
|
+
window.location.href = pushState;
|
|
10665
|
+
}
|
|
10666
|
+
else {
|
|
10667
|
+
window.location.reload();
|
|
10668
|
+
}
|
|
10669
|
+
});
|
|
10670
|
+
}
|
|
10671
|
+
// ── navigate ──────────────────────────────────────────────────────────
|
|
10482
10672
|
function navigate(url) {
|
|
10483
10673
|
try {
|
|
10484
|
-
|
|
10485
|
-
|
|
10674
|
+
const targetUrl = new URL(url, location.href);
|
|
10675
|
+
const sameOrigin = targetUrl.origin === location.origin;
|
|
10676
|
+
if (sameOrigin) {
|
|
10677
|
+
// Soft navigate: fetch + inject + document.write, then pushState
|
|
10678
|
+
// Schedule after RPC response is sent
|
|
10679
|
+
setTimeout(() => softReplace(targetUrl.href, targetUrl.href), 150);
|
|
10680
|
+
return {
|
|
10681
|
+
success: true,
|
|
10682
|
+
message: `Navigating to ${url} (debugger will auto-reconnect)`,
|
|
10683
|
+
};
|
|
10684
|
+
}
|
|
10685
|
+
else {
|
|
10686
|
+
// Cross-origin: can't soft navigate, fall back to hard
|
|
10687
|
+
window.location.href = url;
|
|
10688
|
+
return {
|
|
10689
|
+
success: true,
|
|
10690
|
+
message: `Navigating to ${url} (cross-origin, debugger will disconnect)`,
|
|
10691
|
+
};
|
|
10692
|
+
}
|
|
10486
10693
|
}
|
|
10487
10694
|
catch (err) {
|
|
10488
|
-
return {
|
|
10695
|
+
return {
|
|
10696
|
+
success: false,
|
|
10697
|
+
message: `Navigation failed: ${err.message ?? err}`,
|
|
10698
|
+
};
|
|
10489
10699
|
}
|
|
10490
10700
|
}
|
|
10491
10701
|
navigate.__schema__ = {
|
|
10492
10702
|
name: "navigate",
|
|
10493
|
-
description: "Navigate the browser to a new URL.",
|
|
10703
|
+
description: "Navigate the browser to a new URL. For same-origin URLs, the debugger auto-reconnects. Cross-origin navigation will disconnect the debugger.",
|
|
10494
10704
|
parameters: {
|
|
10495
10705
|
type: "object",
|
|
10496
10706
|
properties: {
|
|
@@ -10502,6 +10712,75 @@
|
|
|
10502
10712
|
required: ["url"],
|
|
10503
10713
|
},
|
|
10504
10714
|
};
|
|
10715
|
+
// ── goBack / goForward ───────────────────────────────────────────────
|
|
10716
|
+
function goBack() {
|
|
10717
|
+
try {
|
|
10718
|
+
window.history.back();
|
|
10719
|
+
return {
|
|
10720
|
+
success: true,
|
|
10721
|
+
message: "Navigated back (re-click bookmarklet to reconnect if needed)",
|
|
10722
|
+
};
|
|
10723
|
+
}
|
|
10724
|
+
catch (err) {
|
|
10725
|
+
return {
|
|
10726
|
+
success: false,
|
|
10727
|
+
message: `Back navigation failed: ${err.message ?? err}`,
|
|
10728
|
+
};
|
|
10729
|
+
}
|
|
10730
|
+
}
|
|
10731
|
+
goBack.__schema__ = {
|
|
10732
|
+
name: "goBack",
|
|
10733
|
+
description: "Navigate back in browser history. The debugger may disconnect — re-click the bookmarklet to reconnect.",
|
|
10734
|
+
parameters: {
|
|
10735
|
+
type: "object",
|
|
10736
|
+
properties: {},
|
|
10737
|
+
},
|
|
10738
|
+
};
|
|
10739
|
+
function goForward() {
|
|
10740
|
+
try {
|
|
10741
|
+
window.history.forward();
|
|
10742
|
+
return {
|
|
10743
|
+
success: true,
|
|
10744
|
+
message: "Navigated forward (re-click bookmarklet to reconnect if needed)",
|
|
10745
|
+
};
|
|
10746
|
+
}
|
|
10747
|
+
catch (err) {
|
|
10748
|
+
return {
|
|
10749
|
+
success: false,
|
|
10750
|
+
message: `Forward navigation failed: ${err.message ?? err}`,
|
|
10751
|
+
};
|
|
10752
|
+
}
|
|
10753
|
+
}
|
|
10754
|
+
goForward.__schema__ = {
|
|
10755
|
+
name: "goForward",
|
|
10756
|
+
description: "Navigate forward in browser history. The debugger may disconnect — re-click the bookmarklet to reconnect.",
|
|
10757
|
+
parameters: {
|
|
10758
|
+
type: "object",
|
|
10759
|
+
properties: {},
|
|
10760
|
+
},
|
|
10761
|
+
};
|
|
10762
|
+
// ── reload ───────────────────────────────────────────────────────────
|
|
10763
|
+
function reload() {
|
|
10764
|
+
try {
|
|
10765
|
+
// Schedule soft reload after RPC response is sent
|
|
10766
|
+
setTimeout(() => softReplace(location.href), 150);
|
|
10767
|
+
return {
|
|
10768
|
+
success: true,
|
|
10769
|
+
message: "Reloading page (debugger will auto-reconnect)",
|
|
10770
|
+
};
|
|
10771
|
+
}
|
|
10772
|
+
catch (err) {
|
|
10773
|
+
return { success: false, message: `Reload failed: ${err.message ?? err}` };
|
|
10774
|
+
}
|
|
10775
|
+
}
|
|
10776
|
+
reload.__schema__ = {
|
|
10777
|
+
name: "reload",
|
|
10778
|
+
description: "Reload the current page. The debugger auto-reconnects after reload using soft page replacement.",
|
|
10779
|
+
parameters: {
|
|
10780
|
+
type: "object",
|
|
10781
|
+
properties: {},
|
|
10782
|
+
},
|
|
10783
|
+
};
|
|
10505
10784
|
|
|
10506
10785
|
/**
|
|
10507
10786
|
* React component tree inspection service.
|
|
@@ -10844,6 +11123,33 @@
|
|
|
10844
11123
|
return [frontmatter, intro, functionDocs.join("\n"), tips].join("\n");
|
|
10845
11124
|
}
|
|
10846
11125
|
|
|
11126
|
+
/**
|
|
11127
|
+
* Wrap a function with correct, unminified parameter names for hypha-rpc.
|
|
11128
|
+
*
|
|
11129
|
+
* In production builds, Babel/Terser minifies parameter names (e.g. 'code' → 'e').
|
|
11130
|
+
* hypha-rpc's getParamNames() parses Function.toString() to map kwargs to
|
|
11131
|
+
* positional args. With minified names, kwargs like {code: '...'} can't be
|
|
11132
|
+
* mapped and args are silently dropped.
|
|
11133
|
+
*
|
|
11134
|
+
* This helper uses new Function() to create a wrapper whose parameter names
|
|
11135
|
+
* are taken from the function's __schema__ property, so hypha-rpc always sees
|
|
11136
|
+
* the real parameter names regardless of minification.
|
|
11137
|
+
*/
|
|
11138
|
+
function wrapFn(fn) {
|
|
11139
|
+
const schema = fn.__schema__;
|
|
11140
|
+
const paramNames = schema?.parameters?.properties
|
|
11141
|
+
? Object.keys(schema.parameters.properties)
|
|
11142
|
+
: [];
|
|
11143
|
+
if (paramNames.length === 0) {
|
|
11144
|
+
return fn;
|
|
11145
|
+
}
|
|
11146
|
+
const paramList = paramNames.join(", ");
|
|
11147
|
+
const wrapper = new Function("fn", `return async function(${paramList}) { return fn(${paramList}); }`)(fn);
|
|
11148
|
+
if (schema)
|
|
11149
|
+
wrapper.__schema__ = schema;
|
|
11150
|
+
return wrapper;
|
|
11151
|
+
}
|
|
11152
|
+
|
|
10847
11153
|
/**
|
|
10848
11154
|
* @file port from browser-use
|
|
10849
11155
|
* @see https://github.com/browser-use/browser-use/commits/main/browser_use/dom/dom_tree/index.js
|
|
@@ -13580,12 +13886,15 @@
|
|
|
13580
13886
|
crypto.getRandomValues(arr);
|
|
13581
13887
|
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
13582
13888
|
}
|
|
13889
|
+
/** sessionStorage key for persisting debugger config across reloads. */
|
|
13890
|
+
const STORAGE_KEY = "__hypha_debugger_config__";
|
|
13583
13891
|
class HyphaDebugger {
|
|
13584
13892
|
constructor(config) {
|
|
13585
13893
|
this.overlay = null;
|
|
13586
13894
|
this.cursor = null;
|
|
13587
13895
|
this.server = null;
|
|
13588
13896
|
this.serviceInfo = null;
|
|
13897
|
+
this.boundBeforeUnload = null;
|
|
13589
13898
|
const requireToken = config.require_token ?? false;
|
|
13590
13899
|
// Always append random suffix unless user provided a custom id.
|
|
13591
13900
|
let serviceId = config.service_id ?? "web-debugger";
|
|
@@ -13645,6 +13954,10 @@
|
|
|
13645
13954
|
// Store globally
|
|
13646
13955
|
w.__HYPHA_DEBUGGER__ = w.__HYPHA_DEBUGGER__ ?? {};
|
|
13647
13956
|
w.__HYPHA_DEBUGGER__.instance = this;
|
|
13957
|
+
// Persist config to sessionStorage for auto-reconnect after reload
|
|
13958
|
+
this.saveConfigToStorage();
|
|
13959
|
+
this.boundBeforeUnload = () => this.saveConfigToStorage();
|
|
13960
|
+
window.addEventListener("beforeunload", this.boundBeforeUnload);
|
|
13648
13961
|
return session;
|
|
13649
13962
|
}
|
|
13650
13963
|
catch (err) {
|
|
@@ -13660,6 +13973,11 @@
|
|
|
13660
13973
|
}
|
|
13661
13974
|
}
|
|
13662
13975
|
async destroy() {
|
|
13976
|
+
// Remove beforeunload listener
|
|
13977
|
+
if (this.boundBeforeUnload) {
|
|
13978
|
+
window.removeEventListener("beforeunload", this.boundBeforeUnload);
|
|
13979
|
+
this.boundBeforeUnload = null;
|
|
13980
|
+
}
|
|
13663
13981
|
try {
|
|
13664
13982
|
if (this.serviceInfo && this.server) {
|
|
13665
13983
|
await this.server.unregisterService(this.serviceInfo.id);
|
|
@@ -13668,6 +13986,13 @@
|
|
|
13668
13986
|
catch {
|
|
13669
13987
|
// Ignore unregister errors on cleanup
|
|
13670
13988
|
}
|
|
13989
|
+
// Clear sessionStorage config (explicit destroy = user wants to stop)
|
|
13990
|
+
try {
|
|
13991
|
+
sessionStorage.removeItem(STORAGE_KEY);
|
|
13992
|
+
}
|
|
13993
|
+
catch {
|
|
13994
|
+
// ignore
|
|
13995
|
+
}
|
|
13671
13996
|
disposeController();
|
|
13672
13997
|
this.cursor?.destroy();
|
|
13673
13998
|
this.cursor = null;
|
|
@@ -13679,6 +14004,48 @@
|
|
|
13679
14004
|
delete w.__HYPHA_DEBUGGER__.session;
|
|
13680
14005
|
}
|
|
13681
14006
|
}
|
|
14007
|
+
/**
|
|
14008
|
+
* Persist debugger config to sessionStorage so the debugger can
|
|
14009
|
+
* auto-reconnect after a page reload (soft reload injects the script,
|
|
14010
|
+
* autoStart() reads this config).
|
|
14011
|
+
*/
|
|
14012
|
+
saveConfigToStorage() {
|
|
14013
|
+
try {
|
|
14014
|
+
const data = {
|
|
14015
|
+
server_url: this.config.server_url,
|
|
14016
|
+
workspace: this.server?.config?.workspace ?? this.config.workspace,
|
|
14017
|
+
token: this.config.token,
|
|
14018
|
+
service_id: this.config.service_id,
|
|
14019
|
+
service_name: this.config.service_name,
|
|
14020
|
+
show_ui: this.config.show_ui,
|
|
14021
|
+
visibility: this.config.visibility,
|
|
14022
|
+
require_token: this.config.require_token,
|
|
14023
|
+
script_url: this.detectScriptUrl(),
|
|
14024
|
+
};
|
|
14025
|
+
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
14026
|
+
}
|
|
14027
|
+
catch {
|
|
14028
|
+
// sessionStorage might be unavailable (private browsing, full quota)
|
|
14029
|
+
}
|
|
14030
|
+
}
|
|
14031
|
+
/**
|
|
14032
|
+
* Detect the URL of the currently loaded hypha-debugger script.
|
|
14033
|
+
* Used by navigate.ts to inject the correct script after soft reload.
|
|
14034
|
+
*/
|
|
14035
|
+
detectScriptUrl() {
|
|
14036
|
+
try {
|
|
14037
|
+
const scripts = document.querySelectorAll("script[src]");
|
|
14038
|
+
for (const s of Array.from(scripts)) {
|
|
14039
|
+
if (s.src && s.src.includes("hypha-debugger")) {
|
|
14040
|
+
return s.src;
|
|
14041
|
+
}
|
|
14042
|
+
}
|
|
14043
|
+
}
|
|
14044
|
+
catch {
|
|
14045
|
+
// ignore
|
|
14046
|
+
}
|
|
14047
|
+
return "https://cdn.jsdelivr.net/npm/hypha-debugger/dist/hypha-debugger.min.js";
|
|
14048
|
+
}
|
|
13682
14049
|
/**
|
|
13683
14050
|
* Generate token, build service URL, update overlay instructions, and
|
|
13684
14051
|
* return a DebugSession.
|
|
@@ -13848,21 +14215,17 @@
|
|
|
13848
14215
|
return lines.join("\n");
|
|
13849
14216
|
}
|
|
13850
14217
|
/**
|
|
13851
|
-
* Wrap a service function with logging
|
|
14218
|
+
* Wrap a service function with overlay logging + correct parameter names.
|
|
13852
14219
|
*
|
|
13853
|
-
*
|
|
13854
|
-
*
|
|
13855
|
-
*
|
|
13856
|
-
*
|
|
13857
|
-
*
|
|
14220
|
+
* Adds logging around the function, then applies baseWrapFn() which uses
|
|
14221
|
+
* new Function() to create a wrapper with unminified parameter names from
|
|
14222
|
+
* __schema__. This is critical for production builds where Babel/Terser
|
|
14223
|
+
* minifies parameter names — hypha-rpc's getParamNames() parses
|
|
14224
|
+
* Function.toString() to map kwargs to positional args.
|
|
13858
14225
|
*/
|
|
13859
14226
|
wrapFn(fn, name) {
|
|
13860
|
-
const schema = fn.__schema__;
|
|
13861
|
-
const paramNames = schema?.parameters?.properties
|
|
13862
|
-
? Object.keys(schema.parameters.properties)
|
|
13863
|
-
: [];
|
|
13864
14227
|
const self = this;
|
|
13865
|
-
const
|
|
14228
|
+
const logged = async (...args) => {
|
|
13866
14229
|
self.overlay?.addLog(`${name}(${self.summarizeArgs(args)})`, "call");
|
|
13867
14230
|
try {
|
|
13868
14231
|
const result = await fn(...args);
|
|
@@ -13880,19 +14243,10 @@
|
|
|
13880
14243
|
throw err;
|
|
13881
14244
|
}
|
|
13882
14245
|
};
|
|
13883
|
-
|
|
13884
|
-
if (
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
else {
|
|
13888
|
-
// Create a function with explicit, unminified parameter names so
|
|
13889
|
-
// hypha-rpc can parse them from Function.toString().
|
|
13890
|
-
const paramList = paramNames.join(", ");
|
|
13891
|
-
wrapper = new Function("callAndLog", `return async function(${paramList}) { return callAndLog([${paramList}]); }`)(callAndLog);
|
|
13892
|
-
}
|
|
13893
|
-
if (schema)
|
|
13894
|
-
wrapper.__schema__ = schema;
|
|
13895
|
-
return wrapper;
|
|
14246
|
+
// Preserve __schema__ so baseWrapFn can read parameter names
|
|
14247
|
+
if (fn.__schema__)
|
|
14248
|
+
logged.__schema__ = fn.__schema__;
|
|
14249
|
+
return wrapFn(logged);
|
|
13896
14250
|
}
|
|
13897
14251
|
summarizeArgs(args) {
|
|
13898
14252
|
if (args.length === 0)
|
|
@@ -13922,7 +14276,11 @@
|
|
|
13922
14276
|
* Programmatic usage:
|
|
13923
14277
|
* import { startDebugger } from 'hypha-debugger';
|
|
13924
14278
|
* const session = await startDebugger({ server_url: 'https://hypha.aicell.io' });
|
|
14279
|
+
*
|
|
14280
|
+
* Library usage (import individual functions):
|
|
14281
|
+
* import { getPageInfo, clickElement, wrapFn, PageController } from 'hypha-debugger';
|
|
13925
14282
|
*/
|
|
14283
|
+
// ── Core debugger ──
|
|
13926
14284
|
/**
|
|
13927
14285
|
* Start the Hypha debugger. Connects to a Hypha server and registers
|
|
13928
14286
|
* a debug service that remote clients can use to inspect and interact
|
|
@@ -13943,6 +14301,26 @@
|
|
|
13943
14301
|
function autoStart() {
|
|
13944
14302
|
if (typeof window === "undefined" || typeof document === "undefined")
|
|
13945
14303
|
return;
|
|
14304
|
+
// Skip if already started
|
|
14305
|
+
if (window.__HYPHA_DEBUGGER__?.instance)
|
|
14306
|
+
return;
|
|
14307
|
+
// Check sessionStorage for saved config (auto-reconnect after soft reload)
|
|
14308
|
+
try {
|
|
14309
|
+
const saved = sessionStorage.getItem("__hypha_debugger_config__");
|
|
14310
|
+
if (saved) {
|
|
14311
|
+
const savedConfig = JSON.parse(saved);
|
|
14312
|
+
if (savedConfig.server_url) {
|
|
14313
|
+
console.log("[hypha-debugger] Reconnecting from saved session...");
|
|
14314
|
+
startDebugger(savedConfig).catch((err) => {
|
|
14315
|
+
console.error("[hypha-debugger] Auto-reconnect failed:", err);
|
|
14316
|
+
});
|
|
14317
|
+
return;
|
|
14318
|
+
}
|
|
14319
|
+
}
|
|
14320
|
+
}
|
|
14321
|
+
catch {
|
|
14322
|
+
// sessionStorage not available or parse error — continue to script tag detection
|
|
14323
|
+
}
|
|
13946
14324
|
// Find our own script tag
|
|
13947
14325
|
const scripts = document.querySelectorAll("script[src]");
|
|
13948
14326
|
let scriptEl = null;
|
|
@@ -13955,9 +14333,6 @@
|
|
|
13955
14333
|
// Skip if data-manual is set
|
|
13956
14334
|
if (scriptEl?.hasAttribute("data-manual"))
|
|
13957
14335
|
return;
|
|
13958
|
-
// Skip if already started
|
|
13959
|
-
if (window.__HYPHA_DEBUGGER__?.instance)
|
|
13960
|
-
return;
|
|
13961
14336
|
const serverUrl = scriptEl?.getAttribute("data-server-url") ?? "https://hypha.aicell.io";
|
|
13962
14337
|
const config = {
|
|
13963
14338
|
server_url: serverUrl,
|
|
@@ -13991,8 +14366,36 @@
|
|
|
13991
14366
|
}
|
|
13992
14367
|
}
|
|
13993
14368
|
|
|
14369
|
+
exports.AICursor = AICursor;
|
|
13994
14370
|
exports.HyphaDebugger = HyphaDebugger;
|
|
14371
|
+
exports.PageController = PageController;
|
|
14372
|
+
exports.clickElement = clickElement$1;
|
|
14373
|
+
exports.clickElementByIndex = clickElementByIndex;
|
|
14374
|
+
exports.disposeController = disposeController;
|
|
14375
|
+
exports.executeScript = executeScript;
|
|
14376
|
+
exports.fillInput = fillInput;
|
|
14377
|
+
exports.generateSkillMd = generateSkillMd;
|
|
14378
|
+
exports.getBrowserState = getBrowserState;
|
|
14379
|
+
exports.getComputedStyles = getComputedStyles;
|
|
14380
|
+
exports.getConsoleLogs = getConsoleLogs;
|
|
14381
|
+
exports.getElementBounds = getElementBounds;
|
|
14382
|
+
exports.getHtml = getHtml;
|
|
14383
|
+
exports.getPageInfo = getPageInfo;
|
|
14384
|
+
exports.getReactTree = getReactTree;
|
|
14385
|
+
exports.goBack = goBack;
|
|
14386
|
+
exports.goForward = goForward;
|
|
14387
|
+
exports.inputText = inputText;
|
|
14388
|
+
exports.installConsoleCapture = installConsoleCapture;
|
|
14389
|
+
exports.navigate = navigate;
|
|
14390
|
+
exports.queryDom = queryDom;
|
|
14391
|
+
exports.reload = reload;
|
|
14392
|
+
exports.removeHighlights = removeHighlights;
|
|
14393
|
+
exports.scroll = scroll;
|
|
14394
|
+
exports.scrollTo = scrollTo;
|
|
14395
|
+
exports.selectOption = selectOption;
|
|
13995
14396
|
exports.startDebugger = startDebugger;
|
|
14397
|
+
exports.takeScreenshot = takeScreenshot;
|
|
14398
|
+
exports.wrapFn = wrapFn;
|
|
13996
14399
|
|
|
13997
14400
|
}));
|
|
13998
14401
|
//# sourceMappingURL=hypha-debugger.js.map
|