haltija 1.1.21 → 1.2.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/apps/desktop/index.html +1 -1
- package/apps/desktop/main.js +264 -64
- package/apps/desktop/package.json +11 -3
- package/apps/desktop/preload.js +17 -0
- package/apps/desktop/renderer/agent-status.js +210 -0
- package/apps/desktop/renderer/settings.js +55 -0
- package/apps/desktop/renderer/state.js +98 -0
- package/apps/desktop/renderer/status.js +38 -0
- package/apps/desktop/renderer/tabs.js +374 -0
- package/apps/desktop/renderer/ui-utils.js +180 -0
- package/apps/desktop/renderer/video-capture.js +154 -0
- package/apps/desktop/renderer/webview-events.js +225 -0
- package/apps/desktop/renderer.js +98 -1604
- package/apps/desktop/resources/component.js +265 -55
- package/apps/desktop/webview-preload.js +19 -1
- package/bin/cli-subcommand.mjs +90 -27
- package/bin/hints.json +9 -4
- package/bin/hj.mjs +61 -2
- package/bin/test-data.mjs +291 -0
- package/bin/tosijs-dev.mjs +95 -20
- package/dist/client.js +5 -1
- package/dist/component.js +265 -55
- package/dist/index.js +444 -76
- package/dist/server.js +444 -76
- package/package.json +2 -1
|
@@ -3,27 +3,37 @@
|
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
|
|
6
|
+
function __accessProp(key) {
|
|
7
|
+
return this[key];
|
|
8
|
+
}
|
|
7
9
|
var __toCommonJS = (from) => {
|
|
8
|
-
var entry = __moduleCache.get(from), desc;
|
|
10
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
9
11
|
if (entry)
|
|
10
12
|
return entry;
|
|
11
13
|
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (var key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(entry, key))
|
|
17
|
+
__defProp(entry, key, {
|
|
18
|
+
get: __accessProp.bind(from, key),
|
|
19
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
+
});
|
|
21
|
+
}
|
|
17
22
|
__moduleCache.set(from, entry);
|
|
18
23
|
return entry;
|
|
19
24
|
};
|
|
25
|
+
var __moduleCache;
|
|
26
|
+
var __returnValue = (v) => v;
|
|
27
|
+
function __exportSetter(name, newValue) {
|
|
28
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
29
|
+
}
|
|
20
30
|
var __export = (target, all) => {
|
|
21
31
|
for (var name in all)
|
|
22
32
|
__defProp(target, name, {
|
|
23
33
|
get: all[name],
|
|
24
34
|
enumerable: true,
|
|
25
35
|
configurable: true,
|
|
26
|
-
set: (
|
|
36
|
+
set: __exportSetter.bind(all, name)
|
|
27
37
|
});
|
|
28
38
|
};
|
|
29
39
|
|
|
@@ -36,7 +46,7 @@
|
|
|
36
46
|
});
|
|
37
47
|
|
|
38
48
|
// src/version.ts
|
|
39
|
-
var VERSION = "1.
|
|
49
|
+
var VERSION = "1.2.2";
|
|
40
50
|
|
|
41
51
|
// src/text-selector.ts
|
|
42
52
|
var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\(/;
|
|
@@ -545,6 +555,40 @@
|
|
|
545
555
|
const candidates = document.querySelectorAll(parsed.baseSelector);
|
|
546
556
|
return Array.from(candidates).filter((el) => elementTextMatches(el, parsed));
|
|
547
557
|
}
|
|
558
|
+
function resolveRefOrSelector(ref, selector) {
|
|
559
|
+
if (ref) {
|
|
560
|
+
const result2 = refRegistry.resolveWithStatus(ref);
|
|
561
|
+
if (result2.element) {
|
|
562
|
+
stats.refsResolved++;
|
|
563
|
+
return { element: result2.element, targetDesc: `@${ref}` };
|
|
564
|
+
}
|
|
565
|
+
stats.refsStale++;
|
|
566
|
+
const errorMsg = result2.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result2.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
|
|
567
|
+
return { element: null, targetDesc: `@${ref}`, error: errorMsg };
|
|
568
|
+
}
|
|
569
|
+
if (selector) {
|
|
570
|
+
const el = resolveSelector(selector);
|
|
571
|
+
return { element: el, targetDesc: selector };
|
|
572
|
+
}
|
|
573
|
+
return { element: null, targetDesc: "(none)", error: "ref or selector is required" };
|
|
574
|
+
}
|
|
575
|
+
function resolveRefOrSelectorAll(ref, selector) {
|
|
576
|
+
if (ref) {
|
|
577
|
+
const result2 = refRegistry.resolveWithStatus(ref);
|
|
578
|
+
if (result2.element) {
|
|
579
|
+
stats.refsResolved++;
|
|
580
|
+
return { elements: [result2.element], targetDesc: `@${ref}` };
|
|
581
|
+
}
|
|
582
|
+
stats.refsStale++;
|
|
583
|
+
const errorMsg = result2.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result2.status === "removed_from_dom" ? `Ref @${ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${ref} is stale - element was garbage collected (try refreshing /tree)`;
|
|
584
|
+
return { elements: [], targetDesc: `@${ref}`, error: errorMsg };
|
|
585
|
+
}
|
|
586
|
+
if (selector) {
|
|
587
|
+
const els = resolveSelectorAll(selector);
|
|
588
|
+
return { elements: els, targetDesc: selector };
|
|
589
|
+
}
|
|
590
|
+
return { elements: [], targetDesc: "(none)", error: "ref or selector is required" };
|
|
591
|
+
}
|
|
548
592
|
function extractElement(el) {
|
|
549
593
|
const rect = el.getBoundingClientRect();
|
|
550
594
|
const attrs = {};
|
|
@@ -1650,6 +1694,10 @@
|
|
|
1650
1694
|
recording = null;
|
|
1651
1695
|
testRecording = null;
|
|
1652
1696
|
originalConsole = {};
|
|
1697
|
+
originalDialogs = {};
|
|
1698
|
+
dialogPolicy = { alert: "dismiss", confirm: "accept", prompt: "dismiss", beforeunload: "allow" };
|
|
1699
|
+
dialogHistory = [];
|
|
1700
|
+
_inHaltijaUI = false;
|
|
1653
1701
|
widgetHidden = false;
|
|
1654
1702
|
serverUrl = "wss://localhost:8700/ws/browser";
|
|
1655
1703
|
windowId;
|
|
@@ -1835,12 +1883,14 @@
|
|
|
1835
1883
|
this.style.bottom = `${this.homeBottom}px`;
|
|
1836
1884
|
this.setupKeyboardShortcut();
|
|
1837
1885
|
this.interceptConsole();
|
|
1886
|
+
this.interceptDialogs();
|
|
1838
1887
|
this.connect();
|
|
1839
1888
|
}
|
|
1840
1889
|
disconnectedCallback() {
|
|
1841
1890
|
this.killed = true;
|
|
1842
1891
|
this.disconnect();
|
|
1843
1892
|
this.restoreConsole();
|
|
1893
|
+
this.restoreDialogs();
|
|
1844
1894
|
this.clearEventWatchers();
|
|
1845
1895
|
this.stopMutationWatch();
|
|
1846
1896
|
}
|
|
@@ -3994,6 +4044,16 @@ ${elementSummary}${moreText}`;
|
|
|
3994
4044
|
return `Interact with ${tag}`;
|
|
3995
4045
|
}
|
|
3996
4046
|
addTestAssertion() {
|
|
4047
|
+
if (!this.testRecording)
|
|
4048
|
+
return;
|
|
4049
|
+
this._inHaltijaUI = true;
|
|
4050
|
+
try {
|
|
4051
|
+
this._addTestAssertionImpl();
|
|
4052
|
+
} finally {
|
|
4053
|
+
this._inHaltijaUI = false;
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
_addTestAssertionImpl() {
|
|
3997
4057
|
if (!this.testRecording)
|
|
3998
4058
|
return;
|
|
3999
4059
|
const type = prompt(`What to check?
|
|
@@ -4068,6 +4128,14 @@ ${elementSummary}${moreText}`;
|
|
|
4068
4128
|
}
|
|
4069
4129
|
}
|
|
4070
4130
|
saveTest() {
|
|
4131
|
+
this._inHaltijaUI = true;
|
|
4132
|
+
try {
|
|
4133
|
+
this._saveTestImpl();
|
|
4134
|
+
} finally {
|
|
4135
|
+
this._inHaltijaUI = false;
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
_saveTestImpl() {
|
|
4071
4139
|
if (!this.testRecording || this.testRecording.steps.length === 0) {
|
|
4072
4140
|
alert("No steps recorded!");
|
|
4073
4141
|
return;
|
|
@@ -5019,9 +5087,80 @@ ${elementSummary}${moreText}`;
|
|
|
5019
5087
|
case "interaction":
|
|
5020
5088
|
this.handleInteractionMessage(msg2);
|
|
5021
5089
|
break;
|
|
5090
|
+
case "dialog":
|
|
5091
|
+
this.handleDialogMessage(msg2);
|
|
5092
|
+
break;
|
|
5093
|
+
case "video":
|
|
5094
|
+
this.handleVideoMessage(msg2);
|
|
5095
|
+
break;
|
|
5022
5096
|
}
|
|
5023
5097
|
this.render();
|
|
5024
5098
|
}
|
|
5099
|
+
handleDialogMessage(msg2) {
|
|
5100
|
+
const { action: action2, payload: payload2 } = msg2;
|
|
5101
|
+
if (action2 === "configure") {
|
|
5102
|
+
if (payload2.alert !== undefined)
|
|
5103
|
+
this.dialogPolicy.alert = payload2.alert;
|
|
5104
|
+
if (payload2.confirm !== undefined)
|
|
5105
|
+
this.dialogPolicy.confirm = payload2.confirm;
|
|
5106
|
+
if (payload2.prompt !== undefined)
|
|
5107
|
+
this.dialogPolicy.prompt = payload2.prompt;
|
|
5108
|
+
if (payload2.beforeunload !== undefined)
|
|
5109
|
+
this.dialogPolicy.beforeunload = payload2.beforeunload;
|
|
5110
|
+
this.respond(msg2.id, true, { policy: this.dialogPolicy });
|
|
5111
|
+
} else if (action2 === "get-config") {
|
|
5112
|
+
this.respond(msg2.id, true, { policy: this.dialogPolicy });
|
|
5113
|
+
} else if (action2 === "history") {
|
|
5114
|
+
this.respond(msg2.id, true, { history: this.dialogHistory });
|
|
5115
|
+
} else {
|
|
5116
|
+
this.respond(msg2.id, false, undefined, `Unknown dialog action: ${action2}`);
|
|
5117
|
+
}
|
|
5118
|
+
}
|
|
5119
|
+
handleVideoMessage(msg2) {
|
|
5120
|
+
const { action: action2, payload: payload2 } = msg2;
|
|
5121
|
+
const haltija = window.haltija;
|
|
5122
|
+
if (action2 === "start") {
|
|
5123
|
+
if (!haltija?.startVideoCapture) {
|
|
5124
|
+
this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
|
|
5125
|
+
return;
|
|
5126
|
+
}
|
|
5127
|
+
haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((result2) => {
|
|
5128
|
+
if (result2.success) {
|
|
5129
|
+
this.respond(msg2.id, true, { recordingId: result2.recordingId });
|
|
5130
|
+
} else {
|
|
5131
|
+
this.respond(msg2.id, false, undefined, result2.error || "Failed to start video");
|
|
5132
|
+
}
|
|
5133
|
+
}).catch((err) => {
|
|
5134
|
+
this.respond(msg2.id, false, undefined, `Failed to start video: ${err.message}`);
|
|
5135
|
+
});
|
|
5136
|
+
} else if (action2 === "stop") {
|
|
5137
|
+
if (!haltija?.stopVideoCapture) {
|
|
5138
|
+
this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
|
|
5139
|
+
return;
|
|
5140
|
+
}
|
|
5141
|
+
haltija.stopVideoCapture().then((result2) => {
|
|
5142
|
+
if (result2.success) {
|
|
5143
|
+
this.respond(msg2.id, true, { path: result2.path, duration: result2.duration, size: result2.size, format: result2.format });
|
|
5144
|
+
} else {
|
|
5145
|
+
this.respond(msg2.id, false, undefined, result2.error || "Failed to stop video");
|
|
5146
|
+
}
|
|
5147
|
+
}).catch((err) => {
|
|
5148
|
+
this.respond(msg2.id, false, undefined, `Failed to stop video: ${err.message}`);
|
|
5149
|
+
});
|
|
5150
|
+
} else if (action2 === "status") {
|
|
5151
|
+
if (!haltija?.videoStatus) {
|
|
5152
|
+
this.respond(msg2.id, true, { recording: false });
|
|
5153
|
+
return;
|
|
5154
|
+
}
|
|
5155
|
+
haltija.videoStatus().then((result2) => {
|
|
5156
|
+
this.respond(msg2.id, true, result2);
|
|
5157
|
+
}).catch(() => {
|
|
5158
|
+
this.respond(msg2.id, true, { recording: false });
|
|
5159
|
+
});
|
|
5160
|
+
} else {
|
|
5161
|
+
this.respond(msg2.id, false, undefined, `Unknown video action: ${action2}`);
|
|
5162
|
+
}
|
|
5163
|
+
}
|
|
5025
5164
|
handleSemanticMessage(msg2) {
|
|
5026
5165
|
const { action: action2, payload: payload2 } = msg2;
|
|
5027
5166
|
if (action2 === "start" || action2 === "watch") {
|
|
@@ -5168,16 +5307,23 @@ ${elementSummary}${moreText}`;
|
|
|
5168
5307
|
if (action2 === "refresh") {
|
|
5169
5308
|
if (payload2.soft) {
|
|
5170
5309
|
location.reload();
|
|
5310
|
+
this.respond(msg2.id, true);
|
|
5171
5311
|
} else {
|
|
5172
|
-
|
|
5173
|
-
|
|
5312
|
+
const haltija = window.haltija;
|
|
5313
|
+
if (haltija?.hardRefresh) {
|
|
5314
|
+
haltija.hardRefresh().then(() => this.respond(msg2.id, true)).catch(() => {
|
|
5315
|
+
location.reload();
|
|
5316
|
+
this.respond(msg2.id, true);
|
|
5317
|
+
});
|
|
5318
|
+
return;
|
|
5319
|
+
}
|
|
5320
|
+
if (typeof caches !== "undefined") {
|
|
5321
|
+
caches.keys().then((names) => Promise.all(names.map((n) => caches.delete(n)))).then(() => location.reload()).catch(() => location.reload());
|
|
5174
5322
|
} else {
|
|
5175
|
-
|
|
5176
|
-
url.searchParams.set("_haltija_refresh", Date.now().toString());
|
|
5177
|
-
location.href = url.toString();
|
|
5323
|
+
location.reload();
|
|
5178
5324
|
}
|
|
5325
|
+
this.respond(msg2.id, true);
|
|
5179
5326
|
}
|
|
5180
|
-
this.respond(msg2.id, true);
|
|
5181
5327
|
} else if (action2 === "goto") {
|
|
5182
5328
|
const haltija = window.haltija;
|
|
5183
5329
|
if (haltija?.navigate) {
|
|
@@ -5238,20 +5384,32 @@ ${elementSummary}${moreText}`;
|
|
|
5238
5384
|
const req = payload2;
|
|
5239
5385
|
try {
|
|
5240
5386
|
if (req.all) {
|
|
5241
|
-
const elements =
|
|
5387
|
+
const { elements, error } = resolveRefOrSelectorAll(req.ref, req.selector);
|
|
5388
|
+
if (error && elements.length === 0) {
|
|
5389
|
+
this.respond(msg2.id, false, null, error);
|
|
5390
|
+
return;
|
|
5391
|
+
}
|
|
5242
5392
|
this.respond(msg2.id, true, elements.map(extractElement));
|
|
5243
5393
|
} else {
|
|
5244
|
-
const
|
|
5245
|
-
|
|
5394
|
+
const { element, targetDesc, error } = resolveRefOrSelector(req.ref, req.selector);
|
|
5395
|
+
if (error) {
|
|
5396
|
+
this.respond(msg2.id, false, null, error);
|
|
5397
|
+
return;
|
|
5398
|
+
}
|
|
5399
|
+
this.respond(msg2.id, true, element ? extractElement(element) : null);
|
|
5246
5400
|
}
|
|
5247
5401
|
} catch (err) {
|
|
5248
5402
|
this.respond(msg2.id, false, null, err.message);
|
|
5249
5403
|
}
|
|
5250
5404
|
} else if (action2 === "inspect") {
|
|
5251
5405
|
try {
|
|
5252
|
-
const el =
|
|
5406
|
+
const { element: el, targetDesc, error } = resolveRefOrSelector(payload2.ref, payload2.selector);
|
|
5407
|
+
if (error) {
|
|
5408
|
+
this.respond(msg2.id, false, null, error);
|
|
5409
|
+
return;
|
|
5410
|
+
}
|
|
5253
5411
|
if (!el) {
|
|
5254
|
-
this.respond(msg2.id, false, null, `Element not found: ${
|
|
5412
|
+
this.respond(msg2.id, false, null, `Element not found: ${targetDesc}`);
|
|
5255
5413
|
return;
|
|
5256
5414
|
}
|
|
5257
5415
|
const opts = {
|
|
@@ -5264,7 +5422,11 @@ ${elementSummary}${moreText}`;
|
|
|
5264
5422
|
}
|
|
5265
5423
|
} else if (action2 === "inspectAll") {
|
|
5266
5424
|
try {
|
|
5267
|
-
const elements =
|
|
5425
|
+
const { elements, error } = resolveRefOrSelectorAll(payload2.ref, payload2.selector);
|
|
5426
|
+
if (error && elements.length === 0) {
|
|
5427
|
+
this.respond(msg2.id, false, null, error);
|
|
5428
|
+
return;
|
|
5429
|
+
}
|
|
5268
5430
|
const opts = {
|
|
5269
5431
|
fullStyles: payload2.fullStyles,
|
|
5270
5432
|
matchedRules: payload2.matchedRules
|
|
@@ -5276,9 +5438,13 @@ ${elementSummary}${moreText}`;
|
|
|
5276
5438
|
}
|
|
5277
5439
|
} else if (action2 === "highlight") {
|
|
5278
5440
|
try {
|
|
5279
|
-
const el =
|
|
5441
|
+
const { element: el, targetDesc, error } = resolveRefOrSelector(payload2.ref, payload2.selector);
|
|
5442
|
+
if (error) {
|
|
5443
|
+
this.respond(msg2.id, false, null, error);
|
|
5444
|
+
return;
|
|
5445
|
+
}
|
|
5280
5446
|
if (!el) {
|
|
5281
|
-
this.respond(msg2.id, false, null, `Element not found: ${
|
|
5447
|
+
this.respond(msg2.id, false, null, `Element not found: ${targetDesc}`);
|
|
5282
5448
|
return;
|
|
5283
5449
|
}
|
|
5284
5450
|
if (payload2.duration) {
|
|
@@ -5286,7 +5452,7 @@ ${elementSummary}${moreText}`;
|
|
|
5286
5452
|
} else {
|
|
5287
5453
|
showHighlight(el, payload2.label, payload2.color);
|
|
5288
5454
|
}
|
|
5289
|
-
this.respond(msg2.id, true, { highlighted:
|
|
5455
|
+
this.respond(msg2.id, true, { highlighted: targetDesc });
|
|
5290
5456
|
} catch (err) {
|
|
5291
5457
|
this.respond(msg2.id, false, null, err.message);
|
|
5292
5458
|
}
|
|
@@ -5413,10 +5579,21 @@ ${elementSummary}${moreText}`;
|
|
|
5413
5579
|
img.src = dataUrl;
|
|
5414
5580
|
});
|
|
5415
5581
|
};
|
|
5582
|
+
let targetSelector = payload2?.selector;
|
|
5583
|
+
if (payload2?.ref) {
|
|
5584
|
+
const { element, targetDesc, error } = resolveRefOrSelector(payload2.ref, undefined);
|
|
5585
|
+
if (error) {
|
|
5586
|
+
this.respond(msg2.id, false, null, error);
|
|
5587
|
+
return;
|
|
5588
|
+
}
|
|
5589
|
+
if (element) {
|
|
5590
|
+
targetSelector = element.id ? `#${element.id}` : element.getAttribute("data-testid") ? `[data-testid="${element.getAttribute("data-testid")}"]` : undefined;
|
|
5591
|
+
}
|
|
5592
|
+
}
|
|
5416
5593
|
const haltija = window.haltija;
|
|
5417
5594
|
if (haltija?.capturePage) {
|
|
5418
5595
|
try {
|
|
5419
|
-
const capturePromise =
|
|
5596
|
+
const capturePromise = targetSelector ? haltija.captureElement(targetSelector) : haltija.capturePage();
|
|
5420
5597
|
const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({ success: false, error: "Screenshot capture timed out after 10s" }), 1e4));
|
|
5421
5598
|
const result2 = await Promise.race([capturePromise, timeoutPromise]);
|
|
5422
5599
|
if (result2?.success && result2.data) {
|
|
@@ -5439,36 +5616,7 @@ ${elementSummary}${moreText}`;
|
|
|
5439
5616
|
return;
|
|
5440
5617
|
}
|
|
5441
5618
|
}
|
|
5442
|
-
|
|
5443
|
-
if (html2canvas) {
|
|
5444
|
-
const target = payload2?.selector ? resolveSelector(payload2.selector) : document.body;
|
|
5445
|
-
if (!target) {
|
|
5446
|
-
this.respond(msg2.id, false, null, `Element not found: ${payload2?.selector}`);
|
|
5447
|
-
return;
|
|
5448
|
-
}
|
|
5449
|
-
const canvas = await html2canvas(target, {
|
|
5450
|
-
useCORS: true,
|
|
5451
|
-
allowTaint: true,
|
|
5452
|
-
logging: false,
|
|
5453
|
-
scale: payload2?.scale || 1
|
|
5454
|
-
});
|
|
5455
|
-
const dataUrl = canvas.toDataURL(mimeType, quality);
|
|
5456
|
-
this.respond(msg2.id, true, {
|
|
5457
|
-
image: dataUrl,
|
|
5458
|
-
viewport,
|
|
5459
|
-
format,
|
|
5460
|
-
width: canvas.width,
|
|
5461
|
-
height: canvas.height,
|
|
5462
|
-
source: "html2canvas"
|
|
5463
|
-
});
|
|
5464
|
-
} else {
|
|
5465
|
-
this.respond(msg2.id, true, {
|
|
5466
|
-
viewport,
|
|
5467
|
-
image: null,
|
|
5468
|
-
note: "Screenshot capture requires the Haltija Desktop app.",
|
|
5469
|
-
source: "viewport-only"
|
|
5470
|
-
});
|
|
5471
|
-
}
|
|
5619
|
+
this.respond(msg2.id, false, null, "Screenshots require the Haltija Desktop app. Run: npx haltija@latest -f");
|
|
5472
5620
|
} catch (err) {
|
|
5473
5621
|
this.respond(msg2.id, false, null, err.message);
|
|
5474
5622
|
}
|
|
@@ -6936,6 +7084,67 @@ ${elementSummary}${moreText}`;
|
|
|
6936
7084
|
}
|
|
6937
7085
|
this.respond(responseId, true);
|
|
6938
7086
|
}
|
|
7087
|
+
interceptDialogs() {
|
|
7088
|
+
this.originalDialogs.alert = window.alert.bind(window);
|
|
7089
|
+
this.originalDialogs.confirm = window.confirm.bind(window);
|
|
7090
|
+
this.originalDialogs.prompt = window.prompt.bind(window);
|
|
7091
|
+
const self = this;
|
|
7092
|
+
window.alert = function(message) {
|
|
7093
|
+
if (self._inHaltijaUI)
|
|
7094
|
+
return self.originalDialogs.alert(message);
|
|
7095
|
+
const msg2 = String(message ?? "");
|
|
7096
|
+
const entry = { type: "alert", message: msg2, response: undefined, timestamp: Date.now() };
|
|
7097
|
+
self.dialogHistory.push(entry);
|
|
7098
|
+
if (self.dialogHistory.length > 50)
|
|
7099
|
+
self.dialogHistory = self.dialogHistory.slice(-25);
|
|
7100
|
+
self.send("dialog", "opened", { type: "alert", message: msg2, windowId: self.windowId });
|
|
7101
|
+
};
|
|
7102
|
+
window.confirm = function(message) {
|
|
7103
|
+
if (self._inHaltijaUI)
|
|
7104
|
+
return self.originalDialogs.confirm(message);
|
|
7105
|
+
const msg2 = String(message ?? "");
|
|
7106
|
+
const accept = self.dialogPolicy.confirm === "accept";
|
|
7107
|
+
const entry = { type: "confirm", message: msg2, response: accept, timestamp: Date.now() };
|
|
7108
|
+
self.dialogHistory.push(entry);
|
|
7109
|
+
if (self.dialogHistory.length > 50)
|
|
7110
|
+
self.dialogHistory = self.dialogHistory.slice(-25);
|
|
7111
|
+
self.send("dialog", "opened", {
|
|
7112
|
+
type: "confirm",
|
|
7113
|
+
message: msg2,
|
|
7114
|
+
response: accept,
|
|
7115
|
+
windowId: self.windowId
|
|
7116
|
+
});
|
|
7117
|
+
return accept;
|
|
7118
|
+
};
|
|
7119
|
+
window.prompt = function(message, defaultValue) {
|
|
7120
|
+
if (self._inHaltijaUI)
|
|
7121
|
+
return self.originalDialogs.prompt(message, defaultValue);
|
|
7122
|
+
const msg2 = String(message ?? "");
|
|
7123
|
+
const policy = self.dialogPolicy.prompt;
|
|
7124
|
+
const response = policy === "dismiss" ? null : policy.response;
|
|
7125
|
+
const entry = { type: "prompt", message: msg2, defaultValue, response, timestamp: Date.now() };
|
|
7126
|
+
self.dialogHistory.push(entry);
|
|
7127
|
+
if (self.dialogHistory.length > 50)
|
|
7128
|
+
self.dialogHistory = self.dialogHistory.slice(-25);
|
|
7129
|
+
self.send("dialog", "opened", {
|
|
7130
|
+
type: "prompt",
|
|
7131
|
+
message: msg2,
|
|
7132
|
+
defaultValue,
|
|
7133
|
+
response,
|
|
7134
|
+
windowId: self.windowId
|
|
7135
|
+
});
|
|
7136
|
+
return response;
|
|
7137
|
+
};
|
|
7138
|
+
}
|
|
7139
|
+
restoreDialogs() {
|
|
7140
|
+
if (this.originalDialogs.alert)
|
|
7141
|
+
window.alert = this.originalDialogs.alert;
|
|
7142
|
+
if (this.originalDialogs.confirm)
|
|
7143
|
+
window.confirm = this.originalDialogs.confirm;
|
|
7144
|
+
if (this.originalDialogs.prompt)
|
|
7145
|
+
window.prompt = this.originalDialogs.prompt;
|
|
7146
|
+
this.originalDialogs = {};
|
|
7147
|
+
}
|
|
6939
7148
|
interceptConsole() {
|
|
6940
7149
|
const levels = [
|
|
6941
7150
|
"log",
|
|
@@ -6994,6 +7203,7 @@ ${elementSummary}${moreText}`;
|
|
|
6994
7203
|
currentTagName = TAG_NAME;
|
|
6995
7204
|
window.__haltija_resolveSelector = resolveSelector;
|
|
6996
7205
|
window.__haltija_resolveSelectorAll = resolveSelectorAll;
|
|
7206
|
+
window.__haltija_refRegistry = refRegistry;
|
|
6997
7207
|
}
|
|
6998
7208
|
registerDevChannel();
|
|
6999
7209
|
var WIDGET_ID = "haltija-widget";
|
|
@@ -24,11 +24,29 @@ contextBridge.exposeInMainWorld('haltija', {
|
|
|
24
24
|
console.log('[Haltija] navigate called:', url)
|
|
25
25
|
return ipcRenderer.invoke('navigate-url', url)
|
|
26
26
|
},
|
|
27
|
-
//
|
|
27
|
+
// Tab management — routed through main process to renderer
|
|
28
|
+
openTab: (url) => ipcRenderer.invoke('open-tab', url),
|
|
29
|
+
closeTab: (windowId) => ipcRenderer.invoke('close-tab', windowId),
|
|
30
|
+
focusTab: (windowId) => ipcRenderer.invoke('focus-tab', windowId),
|
|
28
31
|
openAgentTab: () => {
|
|
29
32
|
console.log('[Haltija] openAgentTab called')
|
|
30
33
|
return ipcRenderer.invoke('open-agent-tab')
|
|
31
34
|
},
|
|
35
|
+
// Hard refresh — bypasses all caches (CSS, JS, images, everything)
|
|
36
|
+
hardRefresh: () => {
|
|
37
|
+
console.log('[Haltija] hardRefresh called')
|
|
38
|
+
return ipcRenderer.invoke('hard-refresh')
|
|
39
|
+
},
|
|
40
|
+
// Video capture — forwarded to renderer via main process
|
|
41
|
+
startVideoCapture: (opts) => {
|
|
42
|
+
return ipcRenderer.invoke('video-start', opts || {})
|
|
43
|
+
},
|
|
44
|
+
stopVideoCapture: () => {
|
|
45
|
+
return ipcRenderer.invoke('video-stop')
|
|
46
|
+
},
|
|
47
|
+
videoStatus: () => {
|
|
48
|
+
return ipcRenderer.invoke('video-status')
|
|
49
|
+
},
|
|
32
50
|
})
|
|
33
51
|
|
|
34
52
|
console.log('[Haltija] Webview preload complete, window.haltija exposed')
|