haltija 1.3.3 → 1.3.4

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haltija-desktop",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "private": true,
5
5
  "description": "Haltija Desktop - God Mode Browser for AI Agents",
6
6
  "homepage": "https://github.com/tonioloewald/haltija",
@@ -46,7 +46,7 @@
46
46
  });
47
47
 
48
48
  // src/version.ts
49
- var VERSION = "1.3.3";
49
+ var VERSION = "1.3.4";
50
50
 
51
51
  // src/text-selector.ts
52
52
  var TEXT_PSEUDO_RE = /:(?:text-is|has-text|text)\(/;
@@ -598,13 +598,13 @@
598
598
  }
599
599
  function resolveRefOrSelector(ref, selector) {
600
600
  if (ref) {
601
- const result2 = refRegistry.resolveWithStatus(ref);
602
- if (result2.element) {
601
+ const result = refRegistry.resolveWithStatus(ref);
602
+ if (result.element) {
603
603
  stats.refsResolved++;
604
- return { element: result2.element, targetDesc: `@${ref}` };
604
+ return { element: result.element, targetDesc: `@${ref}` };
605
605
  }
606
606
  stats.refsStale++;
607
- 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)`;
607
+ const errorMsg = result.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.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)`;
608
608
  return { element: null, targetDesc: `@${ref}`, error: errorMsg };
609
609
  }
610
610
  if (selector) {
@@ -615,13 +615,13 @@
615
615
  }
616
616
  function resolveRefOrSelectorAll(ref, selector) {
617
617
  if (ref) {
618
- const result2 = refRegistry.resolveWithStatus(ref);
619
- if (result2.element) {
618
+ const result = refRegistry.resolveWithStatus(ref);
619
+ if (result.element) {
620
620
  stats.refsResolved++;
621
- return { elements: [result2.element], targetDesc: `@${ref}` };
621
+ return { elements: [result.element], targetDesc: `@${ref}` };
622
622
  }
623
623
  stats.refsStale++;
624
- 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)`;
624
+ const errorMsg = result.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.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)`;
625
625
  return { elements: [], targetDesc: `@${ref}`, error: errorMsg };
626
626
  }
627
627
  if (selector) {
@@ -2870,8 +2870,8 @@
2870
2870
  headers: { "Content-Type": "application/json" },
2871
2871
  body: JSON.stringify({ action: "start", window: this.windowId })
2872
2872
  });
2873
- const result2 = await response.json();
2874
- if (result2.success) {
2873
+ const result = await response.json();
2874
+ if (result.success) {
2875
2875
  this.isRecording = true;
2876
2876
  this.serverManagedRecording = true;
2877
2877
  this.recordingStartTime = Date.now();
@@ -2883,7 +2883,7 @@
2883
2883
  this.updateRecordingUI(true);
2884
2884
  console.log("[Haltija] Recording started (server-managed)");
2885
2885
  } else {
2886
- console.error("[Haltija] Failed to start recording:", result2.error);
2886
+ console.error("[Haltija] Failed to start recording:", result.error);
2887
2887
  }
2888
2888
  } catch (err) {
2889
2889
  console.error("[Haltija] Failed to start recording:", err);
@@ -2898,10 +2898,10 @@
2898
2898
  headers: { "Content-Type": "application/json" },
2899
2899
  body: JSON.stringify({ action: "stop", window: this.windowId })
2900
2900
  });
2901
- const result2 = await response.json();
2902
- if (result2.success && result2.data) {
2903
- this.recordingEvents = result2.data.events || [];
2904
- this.recordingStartTime = result2.data.startTime || this.recordingStartTime;
2901
+ const result = await response.json();
2902
+ if (result.success && result.data) {
2903
+ this.recordingEvents = result.data.events || [];
2904
+ this.recordingStartTime = result.data.startTime || this.recordingStartTime;
2905
2905
  const recordingId = `rec_${this.recordingStartTime}_${Math.random().toString(36).slice(2, 8)}`;
2906
2906
  this.lastRecordingId = recordingId;
2907
2907
  console.log(`[Haltija] Recording stopped (${this.recordingEvents.length} events)`);
@@ -3214,15 +3214,15 @@
3214
3214
  headers: { "Content-Type": "application/json" },
3215
3215
  body: JSON.stringify({ description, agentId })
3216
3216
  });
3217
- const result2 = await response.json();
3218
- if (result2.error) {
3217
+ const result = await response.json();
3218
+ if (result.error) {
3219
3219
  if (successMsg) {
3220
- successMsg.textContent = `⚠️ ${result2.error}`;
3220
+ successMsg.textContent = `⚠️ ${result.error}`;
3221
3221
  successMsg.style.color = "#f59e0b";
3222
3222
  }
3223
3223
  } else {
3224
3224
  if (successMsg) {
3225
- successMsg.textContent = `✓ Sent to ${agentName}${result2.interrupted ? " (interrupted)" : ""}`;
3225
+ successMsg.textContent = `✓ Sent to ${agentName}${result.interrupted ? " (interrupted)" : ""}`;
3226
3226
  successMsg.style.color = "#22c55e";
3227
3227
  }
3228
3228
  setTimeout(() => this.closeTestModal(), 1500);
@@ -3753,13 +3753,13 @@
3753
3753
  const haltija = window.haltija;
3754
3754
  if (haltija?.openAgentTab) {
3755
3755
  newAgentText.textContent = "Creating...";
3756
- const result2 = await haltija.openAgentTab();
3757
- if (result2?.shellId) {
3756
+ const result = await haltija.openAgentTab();
3757
+ if (result?.shellId) {
3758
3758
  await new Promise((r) => setTimeout(r, 300));
3759
3759
  if (type === "selection") {
3760
- this.sendSelectionToAgent(result2.shellId, result2.name || "agent");
3760
+ this.sendSelectionToAgent(result.shellId, result.name || "agent");
3761
3761
  } else if (type === "recording") {
3762
- this.sendRecordingToAgent(result2.shellId, result2.name || "agent");
3762
+ this.sendRecordingToAgent(result.shellId, result.name || "agent");
3763
3763
  }
3764
3764
  } else {
3765
3765
  console.error(`${LOG_PREFIX} Failed to create agent tab`);
@@ -3828,8 +3828,8 @@ ${elementSummary}${moreText}`;
3828
3828
  context: `selection from ${window.location.host}`
3829
3829
  })
3830
3830
  });
3831
- const result2 = await response.json();
3832
- if (result2.sent) {
3831
+ const result = await response.json();
3832
+ if (result.sent) {
3833
3833
  this.clearSelection();
3834
3834
  console.log(`${LOG_PREFIX} Selection sent to ${agentName}`);
3835
3835
  }
@@ -5344,11 +5344,11 @@ ${elementSummary}${moreText}`;
5344
5344
  this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
5345
5345
  return;
5346
5346
  }
5347
- haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((result2) => {
5348
- if (result2.success) {
5349
- this.respond(msg2.id, true, { recordingId: result2.recordingId });
5347
+ haltija.startVideoCapture({ maxDuration: payload2.maxDuration }).then((result) => {
5348
+ if (result.success) {
5349
+ this.respond(msg2.id, true, { recordingId: result.recordingId });
5350
5350
  } else {
5351
- this.respond(msg2.id, false, undefined, result2.error || "Failed to start video");
5351
+ this.respond(msg2.id, false, undefined, result.error || "Failed to start video");
5352
5352
  }
5353
5353
  }).catch((err) => {
5354
5354
  this.respond(msg2.id, false, undefined, `Failed to start video: ${err.message}`);
@@ -5358,11 +5358,11 @@ ${elementSummary}${moreText}`;
5358
5358
  this.respond(msg2.id, false, undefined, "Video capture requires the Haltija Desktop app. Run: npx haltija@latest -f");
5359
5359
  return;
5360
5360
  }
5361
- haltija.stopVideoCapture().then((result2) => {
5362
- if (result2.success) {
5363
- this.respond(msg2.id, true, { path: result2.path, duration: result2.duration, size: result2.size, format: result2.format });
5361
+ haltija.stopVideoCapture().then((result) => {
5362
+ if (result.success) {
5363
+ this.respond(msg2.id, true, { path: result.path, duration: result.duration, size: result.size, format: result.format });
5364
5364
  } else {
5365
- this.respond(msg2.id, false, undefined, result2.error || "Failed to stop video");
5365
+ this.respond(msg2.id, false, undefined, result.error || "Failed to stop video");
5366
5366
  }
5367
5367
  }).catch((err) => {
5368
5368
  this.respond(msg2.id, false, undefined, `Failed to stop video: ${err.message}`);
@@ -5372,8 +5372,8 @@ ${elementSummary}${moreText}`;
5372
5372
  this.respond(msg2.id, true, { recording: false });
5373
5373
  return;
5374
5374
  }
5375
- haltija.videoStatus().then((result2) => {
5376
- this.respond(msg2.id, true, result2);
5375
+ haltija.videoStatus().then((result) => {
5376
+ this.respond(msg2.id, true, result);
5377
5377
  }).catch(() => {
5378
5378
  this.respond(msg2.id, true, { recording: false });
5379
5379
  });
@@ -5390,8 +5390,8 @@ ${elementSummary}${moreText}`;
5390
5390
  this.respond(msg2.id, false, undefined, notAvailable);
5391
5391
  return;
5392
5392
  }
5393
- haltija.networkWatch(payload2 || {}).then((result2) => {
5394
- this.respond(msg2.id, result2.success !== false, result2);
5393
+ haltija.networkWatch(payload2 || {}).then((result) => {
5394
+ this.respond(msg2.id, result.success !== false, result);
5395
5395
  }).catch((err) => {
5396
5396
  this.respond(msg2.id, false, undefined, err.message);
5397
5397
  });
@@ -5400,8 +5400,8 @@ ${elementSummary}${moreText}`;
5400
5400
  this.respond(msg2.id, false, undefined, notAvailable);
5401
5401
  return;
5402
5402
  }
5403
- haltija.networkUnwatch().then((result2) => {
5404
- this.respond(msg2.id, true, result2);
5403
+ haltija.networkUnwatch().then((result) => {
5404
+ this.respond(msg2.id, true, result);
5405
5405
  }).catch((err) => {
5406
5406
  this.respond(msg2.id, false, undefined, err.message);
5407
5407
  });
@@ -5410,8 +5410,8 @@ ${elementSummary}${moreText}`;
5410
5410
  this.respond(msg2.id, false, undefined, notAvailable);
5411
5411
  return;
5412
5412
  }
5413
- haltija.networkLog(payload2 || {}).then((result2) => {
5414
- this.respond(msg2.id, true, result2);
5413
+ haltija.networkLog(payload2 || {}).then((result) => {
5414
+ this.respond(msg2.id, true, result);
5415
5415
  }).catch((err) => {
5416
5416
  this.respond(msg2.id, false, undefined, err.message);
5417
5417
  });
@@ -5420,8 +5420,8 @@ ${elementSummary}${moreText}`;
5420
5420
  this.respond(msg2.id, false, undefined, notAvailable);
5421
5421
  return;
5422
5422
  }
5423
- haltija.networkStats().then((result2) => {
5424
- this.respond(msg2.id, true, result2);
5423
+ haltija.networkStats().then((result) => {
5424
+ this.respond(msg2.id, true, result);
5425
5425
  }).catch((err) => {
5426
5426
  this.respond(msg2.id, false, undefined, err.message);
5427
5427
  });
@@ -5430,8 +5430,8 @@ ${elementSummary}${moreText}`;
5430
5430
  this.respond(msg2.id, false, undefined, notAvailable);
5431
5431
  return;
5432
5432
  }
5433
- haltija.networkClear().then((result2) => {
5434
- this.respond(msg2.id, true, result2);
5433
+ haltija.networkClear().then((result) => {
5434
+ this.respond(msg2.id, true, result);
5435
5435
  }).catch((err) => {
5436
5436
  this.respond(msg2.id, false, undefined, err.message);
5437
5437
  });
@@ -5877,9 +5877,9 @@ ${elementSummary}${moreText}`;
5877
5877
  try {
5878
5878
  const capturePromise = targetSelector ? haltija.captureElement(targetSelector) : haltija.capturePage();
5879
5879
  const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({ success: false, error: "Screenshot capture timed out after 10s" }), 1e4));
5880
- const result2 = await Promise.race([capturePromise, timeoutPromise]);
5881
- if (result2?.success && result2.data) {
5882
- const converted = await convertFormat(result2.data);
5880
+ const result = await Promise.race([capturePromise, timeoutPromise]);
5881
+ if (result?.success && result.data) {
5882
+ const converted = await convertFormat(result.data);
5883
5883
  this.respond(msg2.id, true, {
5884
5884
  image: converted.image,
5885
5885
  viewport,
@@ -5889,8 +5889,8 @@ ${elementSummary}${moreText}`;
5889
5889
  source: "electron"
5890
5890
  });
5891
5891
  return;
5892
- } else if (result2 && !result2.success) {
5893
- this.respond(msg2.id, false, null, result2.error || "Electron capture failed");
5892
+ } else if (result && !result.success) {
5893
+ this.respond(msg2.id, false, null, result.error || "Electron capture failed");
5894
5894
  return;
5895
5895
  }
5896
5896
  } catch (err) {
@@ -5961,14 +5961,29 @@ ${elementSummary}${moreText}`;
5961
5961
  this.respond(msg2.id, true);
5962
5962
  }
5963
5963
  }
5964
- async handleEvalMessage(msg) {
5964
+ async handleEvalMessage(msg2) {
5965
5965
  try {
5966
- const result = eval(msg.payload.code);
5966
+ const result = this.evalCode(msg2.payload.code);
5967
5967
  const resolved = result instanceof Promise ? await result : result;
5968
- this.respond(msg.id, true, resolved);
5968
+ this.respond(msg2.id, true, resolved);
5969
5969
  } catch (err) {
5970
- this.respond(msg.id, false, null, err.message);
5970
+ this.respond(msg2.id, false, null, err.message);
5971
+ }
5972
+ }
5973
+ evalCode(code) {
5974
+ try {
5975
+ return eval(code);
5976
+ } catch (err) {
5977
+ if (!(err instanceof SyntaxError) || !/\b(await|return)\b/.test(code))
5978
+ throw err;
5979
+ }
5980
+ try {
5981
+ return eval(`(async () => (${code}))()`);
5982
+ } catch (err) {
5983
+ if (!(err instanceof SyntaxError))
5984
+ throw err;
5971
5985
  }
5986
+ return eval(`(async () => { ${code} })()`);
5972
5987
  }
5973
5988
  async handleFetchMessage(msg2) {
5974
5989
  const { url } = msg2.payload;
@@ -6046,14 +6061,14 @@ ${elementSummary}${moreText}`;
6046
6061
  let el = null;
6047
6062
  let targetDesc = "";
6048
6063
  if (ref) {
6049
- const result2 = refRegistry.resolveWithStatus(ref);
6050
- el = result2.element;
6064
+ const result = refRegistry.resolveWithStatus(ref);
6065
+ el = result.element;
6051
6066
  targetDesc = `@${ref}`;
6052
6067
  if (el) {
6053
6068
  stats.refsResolved++;
6054
6069
  } else {
6055
6070
  stats.refsStale++;
6056
- 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)`;
6071
+ const errorMsg = result.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.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)`;
6057
6072
  this.respond(responseId, false, null, errorMsg);
6058
6073
  return;
6059
6074
  }
@@ -6398,14 +6413,14 @@ ${elementSummary}${moreText}`;
6398
6413
  let el = null;
6399
6414
  let targetDesc = "";
6400
6415
  if (payload2.ref) {
6401
- const result2 = refRegistry.resolveWithStatus(payload2.ref);
6402
- el = result2.element;
6416
+ const result = refRegistry.resolveWithStatus(payload2.ref);
6417
+ el = result.element;
6403
6418
  targetDesc = `@${payload2.ref}`;
6404
6419
  if (el) {
6405
6420
  stats.refsResolved++;
6406
6421
  } else {
6407
6422
  stats.refsStale++;
6408
- const errorMsg = result2.status === "never_assigned" ? `Ref @${payload2.ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result2.status === "removed_from_dom" ? `Ref @${payload2.ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${payload2.ref} is stale - element was garbage collected (try refreshing /tree)`;
6423
+ const errorMsg = result.status === "never_assigned" ? `Ref @${payload2.ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.status === "removed_from_dom" ? `Ref @${payload2.ref} points to an element that was removed from the DOM (try refreshing /tree)` : `Ref @${payload2.ref} is stale - element was garbage collected (try refreshing /tree)`;
6409
6424
  this.respond(responseId, false, null, errorMsg);
6410
6425
  return;
6411
6426
  }
@@ -6474,15 +6489,15 @@ ${elementSummary}${moreText}`;
6474
6489
  let target = null;
6475
6490
  let targetDesc = "";
6476
6491
  if (ref) {
6477
- const result2 = refRegistry.resolveWithStatus(ref);
6478
- target = result2.element;
6492
+ const result = refRegistry.resolveWithStatus(ref);
6493
+ target = result.element;
6479
6494
  targetDesc = `@${ref}`;
6480
6495
  if (target) {
6481
6496
  stats.refsResolved++;
6482
6497
  target.focus();
6483
6498
  } else {
6484
6499
  stats.refsStale++;
6485
- 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)`;
6500
+ const errorMsg = result.status === "never_assigned" ? `Ref @${ref} was never assigned (highest ref is @${refRegistry.getStats().highWaterMark})` : result.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)`;
6486
6501
  this.respond(responseId, false, null, errorMsg);
6487
6502
  return;
6488
6503
  }
@@ -6874,9 +6889,9 @@ ${elementSummary}${moreText}`;
6874
6889
  });
6875
6890
  } else if (action2 === "result") {
6876
6891
  if (this.selectionResult) {
6877
- const result2 = this.selectionResult;
6892
+ const result = this.selectionResult;
6878
6893
  this.clearSelection();
6879
- this.respond(msg2.id, true, result2);
6894
+ this.respond(msg2.id, true, result);
6880
6895
  } else {
6881
6896
  this.respond(msg2.id, false, null, "No selection available");
6882
6897
  }
@@ -20,7 +20,7 @@
20
20
  * - Option+Tab toggles visibility (but active state always shows briefly)
21
21
  * - Localhost only by default
22
22
  */
23
- export declare const VERSION = "1.3.3";
23
+ export declare const VERSION = "1.3.4";
24
24
  export declare class DevChannel extends HTMLElement {
25
25
  static get tagName(): string;
26
26
  static elementCreator(): () => DevChannel;
@@ -268,6 +268,17 @@ export declare class DevChannel extends HTMLElement {
268
268
  private handleEventsMessage;
269
269
  private handleConsoleMessage;
270
270
  private handleEvalMessage;
271
+ /**
272
+ * Direct `eval` never inherits an async context, so top-level `await` is a
273
+ * SyntaxError no matter what encloses this call — likewise `return`. Retry
274
+ * such code inside an async IIFE: expression position first (it preserves the
275
+ * completion value), statement body second (which needs an explicit `return`).
276
+ *
277
+ * The retry is gated on the code mentioning `await`/`return` because a runtime
278
+ * SyntaxError (`JSON.parse('{')`) is indistinguishable from a parse failure
279
+ * here, and re-running would repeat any side effects the code already had.
280
+ */
281
+ private evalCode;
271
282
  private handleFetchMessage;
272
283
  private handleInteractionMessage;
273
284
  /**