@reticlehq/browser 3.7.0 → 3.8.1

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.
Files changed (104) hide show
  1. package/dist/actions/action-report.d.ts +10 -0
  2. package/dist/actions/action-report.js +59 -14
  3. package/dist/actions/actions-dom.d.ts +4 -0
  4. package/dist/actions/actions-dom.js +20 -4
  5. package/dist/actions/actions.d.ts +1 -0
  6. package/dist/actions/actions.js +94 -46
  7. package/dist/actions/appeared-text.js +2 -2
  8. package/dist/actions/click-target.d.ts +1 -0
  9. package/dist/actions/click-target.js +14 -0
  10. package/dist/actions/danger-context.d.ts +2 -1
  11. package/dist/actions/danger-context.js +43 -17
  12. package/dist/actions/scroll.d.ts +2 -0
  13. package/dist/actions/scroll.js +10 -2
  14. package/dist/activate.d.ts +14 -0
  15. package/dist/activate.js +43 -0
  16. package/dist/busy.d.ts +3 -0
  17. package/dist/busy.js +42 -0
  18. package/dist/commands/commands.js +45 -17
  19. package/dist/connect-options.d.ts +12 -1
  20. package/dist/connect-options.js +18 -1
  21. package/dist/dom/a11y.d.ts +0 -2
  22. package/dist/dom/a11y.js +103 -363
  23. package/dist/dom/chart.d.ts +3 -2
  24. package/dist/dom/chart.js +3 -2
  25. package/dist/dom/dom-ignore.d.ts +6 -0
  26. package/dist/dom/dom-ignore.js +60 -5
  27. package/dist/dom/layout-audit.d.ts +15 -0
  28. package/dist/dom/layout-audit.js +208 -0
  29. package/dist/dom/paint-context.d.ts +15 -0
  30. package/dist/dom/paint-context.js +78 -0
  31. package/dist/dom/query-finders.d.ts +6 -0
  32. package/dist/dom/query-finders.js +216 -0
  33. package/dist/dom/query.d.ts +1 -1
  34. package/dist/dom/query.js +154 -227
  35. package/dist/dom/shadow-registry.d.ts +1 -0
  36. package/dist/dom/shadow-registry.js +27 -0
  37. package/dist/dom/snapshot.d.ts +5 -0
  38. package/dist/dom/snapshot.js +87 -35
  39. package/dist/dom/stable-selector.d.ts +1 -0
  40. package/dist/dom/stable-selector.js +19 -0
  41. package/dist/dom/text-match.d.ts +12 -0
  42. package/dist/dom/text-match.js +115 -0
  43. package/dist/dom/theme.d.ts +1 -0
  44. package/dist/dom/theme.js +21 -9
  45. package/dist/dom/virtualized.js +5 -1
  46. package/dist/dom/visibility.d.ts +7 -0
  47. package/dist/dom/visibility.js +322 -0
  48. package/dist/index.d.ts +4 -2
  49. package/dist/index.js +7 -1
  50. package/dist/observers/blind-spots.js +3 -2
  51. package/dist/observers/canvas.d.ts +18 -0
  52. package/dist/observers/canvas.js +76 -0
  53. package/dist/observers/dom.js +68 -19
  54. package/dist/observers/field.d.ts +11 -0
  55. package/dist/observers/field.js +117 -13
  56. package/dist/observers/install-all.js +4 -0
  57. package/dist/observers/media.d.ts +2 -0
  58. package/dist/observers/media.js +32 -0
  59. package/dist/observers/net-detail/network-body.d.ts +2 -0
  60. package/dist/observers/net-detail/network-body.js +36 -9
  61. package/dist/observers/net-detail/network-event-stream.d.ts +5 -0
  62. package/dist/observers/net-detail/network-event-stream.js +55 -0
  63. package/dist/observers/net-detail/network-frames.d.ts +2 -0
  64. package/dist/observers/net-detail/network-frames.js +39 -0
  65. package/dist/observers/net-detail/network-response-body.d.ts +3 -0
  66. package/dist/observers/net-detail/network-response-body.js +97 -0
  67. package/dist/observers/network.js +111 -101
  68. package/dist/observers/route.d.ts +2 -0
  69. package/dist/observers/route.js +33 -4
  70. package/dist/presenter/chrome/presenter-report-copy.d.ts +0 -5
  71. package/dist/presenter/chrome/presenter-report-copy.js +0 -14
  72. package/dist/presenter/hud-telemetry.js +1 -1
  73. package/dist/presenter/presenter-chat-views.d.ts +3 -4
  74. package/dist/presenter/presenter-chat-views.js +47 -20
  75. package/dist/presenter/presenter-config.d.ts +1 -0
  76. package/dist/presenter/presenter-config.js +1 -0
  77. package/dist/presenter/presenter-frame.d.ts +3 -2
  78. package/dist/presenter/presenter-frame.js +24 -15
  79. package/dist/presenter/presenter-harness-row.d.ts +4 -15
  80. package/dist/presenter/presenter-harness-row.js +11 -50
  81. package/dist/presenter/presenter-report-styles.js +0 -17
  82. package/dist/presenter/presenter-report.d.ts +1 -2
  83. package/dist/presenter/presenter-report.js +4 -54
  84. package/dist/presenter/presenter-run-state.js +2 -1
  85. package/dist/presenter/presenter-settings.d.ts +2 -3
  86. package/dist/presenter/presenter-settings.js +14 -17
  87. package/dist/presenter/presenter-shell.d.ts +6 -4
  88. package/dist/presenter/presenter-shell.js +37 -7
  89. package/dist/presenter/presenter.js +32 -11
  90. package/dist/registry/store-adapters.d.ts +5 -2
  91. package/dist/registry/store-adapters.js +40 -10
  92. package/dist/reticle-inject.js +700 -645
  93. package/dist/reticle.d.ts +4 -2
  94. package/dist/reticle.js +36 -6
  95. package/dist/security/page-location.d.ts +2 -0
  96. package/dist/security/page-location.js +7 -0
  97. package/dist/security/serialization.js +1 -1
  98. package/dist/storage-keys.d.ts +1 -0
  99. package/dist/storage-keys.js +1 -0
  100. package/dist/timers/native/native-timers.d.ts +1 -0
  101. package/dist/timers/native/native-timers.js +5 -0
  102. package/dist/transport/transport.d.ts +1 -0
  103. package/dist/transport/transport.js +18 -0
  104. package/package.json +6 -2
@@ -5,7 +5,7 @@ import { ANNOTATE_BTN_ATTR, CHAT_TOGGLE_ATTR, CLEAR_MARKS_ATTR, MARKERS_BTN_ATTR
5
5
  import { hiIconHtml, hiToggleIconHtml, PRESENTER_ICON_SIZE, PresenterIcon, } from './icons/presenter-icons.js';
6
6
  import { HUD_GLASS_PAINT } from './chrome/presenter-hud-chrome.js';
7
7
  import { LAST_ACTOR_ATTR, LOG_ACTOR } from './chrome/presenter-log.js';
8
- import { HARNESS_COPY_PROMPT_ATTR, HARNESS_LINK_ATTR, HARNESS_LOG_ATTR, HARNESS_OPEN_ATTR, HARNESS_ROW_TEXT, HARNESS_SWITCH_ON_ATTR, HARNESS_TOGGLE_ATTR, creditsShort, harnessFootHtml, harnessRowHtml, HARNESS_ROW_CSS, } from './presenter-harness-row.js';
8
+ import { HARNESS_LINK_ATTR, HARNESS_LOG_ATTR, HARNESS_OPEN_ATTR, HARNESS_ROW_TEXT, HARNESS_SWITCH_ON_ATTR, HARNESS_TOGGLE_ATTR, creditsShort, harnessFootHtml, harnessRowHtml, HARNESS_ROW_CSS, } from './presenter-harness-row.js';
9
9
  import { esc, isSafeDashboardUrl } from './chrome/presenter-safe-html.js';
10
10
  import { morphHtml } from './chrome/presenter-morph.js';
11
11
  import { IMPACT_SEEN_KEY_PREFIX, ReticleStorageKey } from '../storage-keys.js';
@@ -20,9 +20,19 @@ const HARNESS_SETUP_HASH = '#model';
20
20
  const HARNESS_PLAN_PATH = '/settings?group=billing';
21
21
  const HARNESS_STARTING_MS = 20_000;
22
22
  export function platformBase(config, account) {
23
- const base = [config?.platformUrl, account.host].find((url) => url !== undefined && isSafeDashboardUrl(url));
23
+ const base = [consoleOrigin(config?.planUrl), config?.platformUrl, account.host].find((url) => url !== undefined && isSafeDashboardUrl(url));
24
24
  return esc((base ?? DEFAULT_PLATFORM_URL).replace(/\/+$/, ''));
25
25
  }
26
+ function consoleOrigin(planUrl) {
27
+ if (planUrl === undefined || !isSafeDashboardUrl(planUrl))
28
+ return undefined;
29
+ try {
30
+ return new URL(planUrl).origin;
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ }
26
36
  function isHistoricalAnnotation(item) {
27
37
  if ('object' !== typeof item || null === item)
28
38
  return false;
@@ -216,7 +226,6 @@ export class ChatViews {
216
226
  #history = readHistory();
217
227
  #account;
218
228
  #harness;
219
- #gate;
220
229
  #verdicts = 0;
221
230
  #impactOpen = false;
222
231
  #onImpact;
@@ -230,9 +239,13 @@ export class ChatViews {
230
239
  #harnessHtml = '';
231
240
  #harnessPageHtml = '';
232
241
  #linking = false;
242
+ #linkTimer;
233
243
  #agent = new AgentLinkView();
234
244
  #startedAs;
245
+ #last;
235
246
  #starting;
247
+ #lastSeq;
248
+ #pressedAfter;
236
249
  constructor(onImpact, onOpenChat, drive) {
237
250
  this.#onImpact = onImpact;
238
251
  this.#onOpenChat = onOpenChat;
@@ -275,6 +288,13 @@ export class ChatViews {
275
288
  if (linkButton.disabled)
276
289
  return;
277
290
  this.#linking = true;
291
+ if (this.#linkTimer !== undefined)
292
+ clearTimeout(this.#linkTimer);
293
+ this.#linkTimer = setTimeout(() => {
294
+ this.#linkTimer = undefined;
295
+ this.#linking = false;
296
+ this.#paintHarness();
297
+ }, HARNESS_STARTING_MS);
278
298
  this.#drive?.link();
279
299
  this.#paintHarness();
280
300
  return;
@@ -284,6 +304,7 @@ export class ChatViews {
284
304
  if (run.disabled)
285
305
  return;
286
306
  this.#startedAs = this.#personaPick;
307
+ this.#pressedAfter = this.#lastSeq;
287
308
  this.#markStarting(true);
288
309
  this.#drive?.run(personaText(this.#personaPick, this.#customPersona));
289
310
  return;
@@ -292,15 +313,6 @@ export class ChatViews {
292
313
  this.#drive?.stop();
293
314
  return;
294
315
  }
295
- const copy = target.closest(`[${HARNESS_COPY_PROMPT_ATTR}]`);
296
- if (null !== copy) {
297
- const prompt = this.#gate?.prompt;
298
- if (prompt !== undefined)
299
- void navigator.clipboard
300
- ?.writeText(prompt)
301
- .then(() => (copy.textContent = HARNESS_ROW_TEXT.COPIED))
302
- .catch(() => undefined);
303
- }
304
316
  };
305
317
  root
306
318
  .querySelector('[data-reticle-harness-spot]')
@@ -441,11 +453,21 @@ export class ChatViews {
441
453
  nav.hidden = true !== account?.signedIn;
442
454
  this.#paintHarness();
443
455
  }
444
- paintDrive(drive) {
456
+ paintDrive(drive, last) {
445
457
  this.#driving = drive;
446
- if (drive !== undefined)
458
+ const runUrl = last?.runUrl !== undefined && isSafeDashboardUrl(last.runUrl) ? esc(last.runUrl) : undefined;
459
+ this.#last =
460
+ last === undefined
461
+ ? undefined
462
+ : {
463
+ ...(runUrl === undefined ? {} : { runUrl }),
464
+ ...(last.said === undefined ? {} : { said: last.said }),
465
+ };
466
+ this.#lastSeq = last?.seq;
467
+ const answered = last?.seq !== undefined && last.seq !== this.#pressedAfter && this.#starting !== undefined;
468
+ if (drive !== undefined || answered)
447
469
  this.#markStarting(false);
448
- else if (this.#starting === undefined)
470
+ if (drive === undefined && this.#starting === undefined)
449
471
  this.#startedAs = undefined;
450
472
  this.#paintHarness();
451
473
  }
@@ -463,11 +485,14 @@ export class ChatViews {
463
485
  if (on)
464
486
  this.#paintHarness();
465
487
  }
466
- paintHarness(config, gate) {
467
- if (config !== undefined)
488
+ paintHarness(config) {
489
+ if (config !== undefined) {
468
490
  this.#linking = false;
491
+ if (this.#linkTimer !== undefined)
492
+ clearTimeout(this.#linkTimer);
493
+ this.#linkTimer = undefined;
494
+ }
469
495
  this.#harness = config;
470
- this.#gate = gate;
471
496
  this.#paintHarness();
472
497
  }
473
498
  paintImpact(verdicts) {
@@ -522,15 +547,17 @@ export class ChatViews {
522
547
  const state = {
523
548
  account,
524
549
  config,
525
- gate: this.#gate,
526
550
  drive: this.#driving,
527
551
  canDrive: this.#drive !== undefined,
528
552
  pick: this.#personaPick,
529
553
  startedAs: this.#startedAs,
530
554
  setupUrl: `${base}${HARNESS_SETUP_PATH}${project}${HARNESS_SETUP_HASH}`,
531
- planUrl: `${base}${HARNESS_PLAN_PATH}`,
555
+ planUrl: config?.planUrl !== undefined && isSafeDashboardUrl(config.planUrl)
556
+ ? esc(config.planUrl)
557
+ : `${base}${HARNESS_PLAN_PATH}`,
532
558
  linking: this.#linking,
533
559
  starting: this.#starting !== undefined && this.#driving === undefined,
560
+ ...(this.#last === undefined ? {} : { last: this.#last }),
534
561
  };
535
562
  const foot = harnessFootHtml(state);
536
563
  if (foot !== this.#harnessHtml) {
@@ -86,6 +86,7 @@ export declare const SETTINGS_CLOSE_ATTR = "data-reticle-settings-close";
86
86
  export declare const SETTING_KEY_ATTR = "data-reticle-setting";
87
87
  export declare const SETTINGS_STORAGE_KEY: "reticle-presenter-settings";
88
88
  export declare const MINIMISED_STORAGE_KEY: "reticle-presenter-minimised";
89
+ export declare const OPEN_STORAGE_KEY: "reticle-presenter-open";
89
90
  export declare const AMBIENT_GLOW_ATTR = "data-reticle-ambient-glow";
90
91
  export declare const LIVENESS_ATTR = "data-reticle-live";
91
92
  export declare const BLOCK_ATTR = "data-reticle-block";
@@ -64,6 +64,7 @@ export const SETTINGS_CLOSE_ATTR = 'data-reticle-settings-close';
64
64
  export const SETTING_KEY_ATTR = 'data-reticle-setting';
65
65
  export const SETTINGS_STORAGE_KEY = ReticleStorageKey.PRESENTER_SETTINGS;
66
66
  export const MINIMISED_STORAGE_KEY = ReticleStorageKey.PRESENTER_MINIMISED;
67
+ export const OPEN_STORAGE_KEY = ReticleStorageKey.PRESENTER_OPEN;
67
68
  export const AMBIENT_GLOW_ATTR = 'data-reticle-ambient-glow';
68
69
  export const LIVENESS_ATTR = 'data-reticle-live';
69
70
  export const BLOCK_ATTR = 'data-reticle-block';
@@ -4,9 +4,10 @@ export declare const RAIL_SIGNIN_ATTR = "data-reticle-rail-signin";
4
4
  export declare const RAIL_PROMO_ATTR = "data-reticle-rail-promo";
5
5
  export declare const RAIL_TEXT: {
6
6
  readonly TITLE: "Sign in to try Reticle Harness";
7
- readonly DETAIL: "Free Harness credits to start.";
7
+ readonly DETAIL: "Free credits to start.";
8
8
  readonly CTA: "Sign in";
9
9
  };
10
- export declare const RAIL_HTML: string;
10
+ export declare const RAIL_SIGNIN_HTML: string;
11
+ export declare const RAIL_HTML = "<div data-reticle-rail class=\"reticle-rail\" role=\"complementary\" aria-label=\"Reticle\">\n <div data-reticle-rail-promo class=\"reticle-rail-promo\"></div>\n</div>";
11
12
  export declare function paintRail(root: HTMLElement, account: AccountState | undefined): void;
12
13
  export declare const FRAME_CSS: string;
@@ -9,24 +9,25 @@ const PAGE_PANEL_ATTR = 'data-reticle-page-panel';
9
9
  const OVERLAY = 'data-reticle-overlay';
10
10
  export const RAIL_TEXT = {
11
11
  TITLE: 'Sign in to try Reticle Harness',
12
- DETAIL: 'Free Harness credits to start.',
12
+ DETAIL: 'Free credits to start.',
13
13
  CTA: 'Sign in',
14
14
  };
15
- export const RAIL_HTML = `<div ${RAIL_ATTR} class="reticle-rail" role="complementary" aria-label="Reticle">
16
- <div ${RAIL_SIGNIN_ATTR} class="reticle-rail-signin" hidden>
15
+ export const RAIL_SIGNIN_HTML = `<div ${RAIL_SIGNIN_ATTR} class="reticle-rail-signin" hidden>
17
16
  <span class="reticle-rail-copy"><strong>${RAIL_TEXT.TITLE}</strong><span>${RAIL_TEXT.DETAIL}</span></span>
18
17
  <button type="button" ${ACCOUNT_SIGNIN_ATTR} class="reticle-rail-cta" title="${ACCOUNT_TEXT.SIGNIN_TITLE}">${RAIL_TEXT.CTA}</button>
19
- </div>
18
+ </div>`;
19
+ export const RAIL_HTML = `<div ${RAIL_ATTR} class="reticle-rail" role="complementary" aria-label="Reticle">
20
20
  <div ${RAIL_PROMO_ATTR} class="reticle-rail-promo"></div>
21
21
  </div>`;
22
22
  export function paintRail(root, account) {
23
23
  const signin = root.querySelector(`[${RAIL_SIGNIN_ATTR}]`);
24
- const promo = root.querySelector(`[${RAIL_PROMO_ATTR}]`);
24
+ const rail = root.querySelector(`[${RAIL_ATTR}]`);
25
25
  const signedOut = account !== undefined && !account.signedIn;
26
26
  if (signin !== null)
27
27
  signin.hidden = !signedOut;
28
- if (promo !== null)
29
- promo.hidden = signedOut;
28
+ if (rail !== null) {
29
+ rail.hidden = signedOut;
30
+ }
30
31
  }
31
32
  const PAGES = `:is([${CHAT_PANEL_ATTR}],[${PAGE_PANEL_ATTR}],[${REPORT_PANEL_ATTR}],[${SETTINGS_PANEL_ATTR}])`;
32
33
  const ANY_OPEN = `[${OVERLAY}][${MIN_ATTR}="0"]:is([${CHAT_ATTR}="1"],[${PAGE_OPEN_ATTR}],[${REPORT_ATTR}="1"],[${SETTINGS_ATTR}="1"])`;
@@ -158,18 +159,26 @@ ${BELOW} ${PAGES}{bottom:auto;top:calc(100% + 8px + var(--reticle-rail-h) + var(
158
159
  pointer-events:auto;}
159
160
  ${BELOW} [${RAIL_ATTR}]{bottom:auto;top:calc(100% + 8px);}
160
161
  ${ANY_OPEN} [${RAIL_ATTR}]{display:flex;}
162
+ ${ANY_OPEN} [${RAIL_ATTR}][hidden]{display:none;}
163
+ /* No rail, no gap for it: the page sits straight above the toolbar. */
164
+ [${DOCK_ATTR}]:has(> [${RAIL_ATTR}][hidden]){--reticle-rail-h:0px;--reticle-frame-gap:0px;}
161
165
  /* The capsule and the rail share a slot: the capsule is for "nothing open", the rail for "a page is". */
162
166
  ${ANY_OPEN} [${CHAT_PILL_ATTR}]{display:none !important;}
163
167
  [${RAIL_ATTR}] > [hidden]{display:none !important;}
164
- [${RAIL_ATTR}] .reticle-rail-signin,[${RAIL_ATTR}] .reticle-rail-promo{flex:1;min-width:0;}
165
- [${RAIL_ATTR}] .reticle-rail-signin{display:flex;align-items:center;gap:var(--reticle-hud-space-3);}
166
- [${RAIL_ATTR}] .reticle-rail-copy{display:flex;flex:1;min-width:0;flex-direction:column;line-height:1.3;}
167
- [${RAIL_ATTR}] .reticle-rail-copy strong{font-size:var(--reticle-hud-size-sm);font-weight:600;}
168
- [${RAIL_ATTR}] .reticle-rail-copy span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--reticle-hud-size-xs);color:var(--reticle-hud-text-muted);}
169
- [${RAIL_ATTR}] .reticle-rail-cta{flex:none;height:28px;padding:0 var(--reticle-hud-space-3);border:0;border-radius:var(--reticle-hud-radius-pill);
168
+ [${RAIL_ATTR}] .reticle-rail-promo{flex:1;min-width:0;}
169
+ /* The sign-in ask: one row in the Agent Log, above its footer. */
170
+ [${RAIL_SIGNIN_ATTR}]{display:flex;flex:none;align-items:center;gap:var(--reticle-hud-space-3);
171
+ margin:0 var(--reticle-hud-space-3) var(--reticle-hud-space-2);padding:var(--reticle-hud-space-2) var(--reticle-hud-space-3);
172
+ border:1px solid color-mix(in srgb,var(--reticle-hud-brand) 30%,var(--reticle-hud-border));border-radius:var(--reticle-hud-radius-md);
173
+ background:linear-gradient(135deg,var(--reticle-hud-brand-soft),transparent 65%);}
174
+ [${RAIL_SIGNIN_ATTR}][hidden]{display:none;}
175
+ [${RAIL_SIGNIN_ATTR}] .reticle-rail-copy{display:flex;flex:1;min-width:0;flex-direction:column;line-height:1.3;}
176
+ [${RAIL_SIGNIN_ATTR}] .reticle-rail-copy strong{font-size:var(--reticle-hud-size-sm);font-weight:600;}
177
+ [${RAIL_SIGNIN_ATTR}] .reticle-rail-copy span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--reticle-hud-size-xs);color:var(--reticle-hud-text-muted);}
178
+ [${RAIL_SIGNIN_ATTR}] .reticle-rail-cta{flex:none;height:28px;padding:0 var(--reticle-hud-space-3);border:0;border-radius:var(--reticle-hud-radius-pill);
170
179
  background:var(--reticle-hud-brand);color:#160b02;font:inherit;font-size:var(--reticle-hud-size-sm);font-weight:700;cursor:pointer;}
171
- [${RAIL_ATTR}] .reticle-rail-cta:hover{filter:brightness(1.08);}
172
- [${RAIL_ATTR}] .reticle-rail-cta:focus-visible{outline:2px solid var(--reticle-hud-text);outline-offset:2px;}
180
+ [${RAIL_SIGNIN_ATTR}] .reticle-rail-cta:hover{filter:brightness(1.08);}
181
+ [${RAIL_SIGNIN_ATTR}] .reticle-rail-cta:focus-visible{outline:2px solid var(--reticle-hud-text);outline-offset:2px;}
173
182
  /* The promo: one line of copy, its link, and dots. The carousel draws no frame of its own here. */
174
183
  [${RAIL_ATTR}] .reticle-carousel{margin:0;padding:0;border:0;background:none;}
175
184
  [${RAIL_ATTR}] .reticle-carousel-track{height:32px;overflow:hidden;}
@@ -1,4 +1,4 @@
1
- import { type AccountState, type HarnessConfig, type HarnessDrive } from '@reticlehq/core';
1
+ import { type AccountState, type HarnessConfig, type HarnessDrive, type LastDrive } from '@reticlehq/core';
2
2
  import { type Credits } from '@reticlehq/core/hud';
3
3
  export declare const HARNESS_ROW_TEXT: {
4
4
  readonly RUN: "Run Harness";
@@ -10,13 +10,10 @@ export declare const HARNESS_ROW_TEXT: {
10
10
  readonly LINK: "Link this project";
11
11
  readonly LINKING: "Linking…";
12
12
  readonly NOT_ENTITLED: "Harness is not on your plan";
13
- readonly NO_CREDITS: "No Harness credits left";
13
+ readonly NO_CREDITS: "No credits left";
14
14
  readonly NO_PROVIDER: "No model provider set";
15
15
  readonly OFF: "Harness is off";
16
- readonly canSwitchOn: (percent: number) => string;
17
16
  readonly TURN_ON: "Switch on";
18
- readonly COPY_PROMPT: "Copy setup prompt";
19
- readonly COPIED: "Copied";
20
17
  readonly SET_UP: "Set up ↗";
21
18
  readonly PLANS: "See plans ↗";
22
19
  readonly PLAN: "Plan ↗";
@@ -29,29 +26,20 @@ export declare const HARNESS_ROW_TEXT: {
29
26
  readonly FOOT_NO_CREDITS: "No credits";
30
27
  readonly FOOT_NOT_ENTITLED: "Not on your plan";
31
28
  readonly FOOT_NO_PROVIDER: "No model provider";
32
- readonly footSetup: (percent: number) => string;
33
29
  readonly PAGE_TITLE: "Reticle Harness";
34
30
  readonly LOG_LABEL: "What the Harness did";
35
31
  readonly LOG_EMPTY: "Runs show here, step by step.";
36
32
  readonly PAGE_SUBTITLE: "Tests your app by itself";
33
+ readonly RESULT: "See the result ↗";
37
34
  };
38
35
  export declare const HARNESS_SWITCH_ON_ATTR = "data-reticle-harness-switch";
39
36
  export declare const HARNESS_LINK_ATTR = "data-reticle-harness-link";
40
37
  export declare const HARNESS_OPEN_ATTR = "data-reticle-harness-open";
41
38
  export declare const HARNESS_LOG_ATTR = "data-reticle-harness-log";
42
39
  export declare const HARNESS_TOGGLE_ATTR = "data-reticle-harness-toggle";
43
- export declare const HARNESS_COPY_PROMPT_ATTR = "data-reticle-harness-copy-prompt";
44
- export interface HarnessGateView {
45
- percent: number;
46
- unlocked: boolean;
47
- reason?: string;
48
- prompt?: string;
49
- }
50
- export declare function harnessGateIn(instrumentation: Readonly<Record<string, unknown>> | undefined, config?: HarnessConfig): HarnessGateView | undefined;
51
40
  export interface HarnessRowState {
52
41
  account: AccountState | undefined;
53
42
  config: HarnessConfig | undefined;
54
- gate?: HarnessGateView | undefined;
55
43
  drive: HarnessDrive | undefined;
56
44
  canDrive: boolean;
57
45
  pick: string;
@@ -60,6 +48,7 @@ export interface HarnessRowState {
60
48
  planUrl: string;
61
49
  linking?: boolean;
62
50
  starting?: boolean;
51
+ last?: LastDrive;
63
52
  }
64
53
  export declare function creditsShort(credits: Credits | undefined): string;
65
54
  export declare function harnessFootHtml(s: HarnessRowState): string;
@@ -13,13 +13,10 @@ export const HARNESS_ROW_TEXT = {
13
13
  LINK: 'Link this project',
14
14
  LINKING: 'Linking…',
15
15
  NOT_ENTITLED: 'Harness is not on your plan',
16
- NO_CREDITS: 'No Harness credits left',
16
+ NO_CREDITS: 'No credits left',
17
17
  NO_PROVIDER: 'No model provider set',
18
18
  OFF: 'Harness is off',
19
- canSwitchOn: (percent) => `Setup score ${String(percent)}%. Harness is off.`,
20
19
  TURN_ON: 'Switch on',
21
- COPY_PROMPT: 'Copy setup prompt',
22
- COPIED: 'Copied',
23
20
  SET_UP: 'Set up ↗',
24
21
  PLANS: 'See plans ↗',
25
22
  PLAN: 'Plan ↗',
@@ -32,50 +29,17 @@ export const HARNESS_ROW_TEXT = {
32
29
  FOOT_NO_CREDITS: 'No credits',
33
30
  FOOT_NOT_ENTITLED: 'Not on your plan',
34
31
  FOOT_NO_PROVIDER: 'No model provider',
35
- footSetup: (percent) => `Setup ${String(percent)}% · needs 80%`,
36
32
  PAGE_TITLE: 'Reticle Harness',
37
33
  LOG_LABEL: 'What the Harness did',
38
34
  LOG_EMPTY: 'Runs show here, step by step.',
39
35
  PAGE_SUBTITLE: 'Tests your app by itself',
36
+ RESULT: 'See the result ↗',
40
37
  };
41
38
  export const HARNESS_SWITCH_ON_ATTR = 'data-reticle-harness-switch';
42
39
  export const HARNESS_LINK_ATTR = 'data-reticle-harness-link';
43
40
  export const HARNESS_OPEN_ATTR = 'data-reticle-harness-open';
44
41
  export const HARNESS_LOG_ATTR = 'data-reticle-harness-log';
45
42
  export const HARNESS_TOGGLE_ATTR = 'data-reticle-harness-toggle';
46
- export const HARNESS_COPY_PROMPT_ATTR = 'data-reticle-harness-copy-prompt';
47
- export function harnessGateIn(instrumentation, config) {
48
- const local = localGateIn(instrumentation);
49
- const platform = config?.gate;
50
- if (platform === undefined)
51
- return local;
52
- const prompt = platform.prompt ?? local?.prompt;
53
- const reason = platform.unlocked ? undefined : (platform.reason ?? local?.reason);
54
- return {
55
- percent: platform.percent ?? local?.percent ?? 0,
56
- unlocked: platform.unlocked,
57
- ...(reason === undefined ? {} : { reason }),
58
- ...(prompt === undefined ? {} : { prompt }),
59
- };
60
- }
61
- function localGateIn(instrumentation) {
62
- const raw = instrumentation?.['harnessGate'];
63
- if ('object' !== typeof raw || null === raw)
64
- return undefined;
65
- const gate = raw;
66
- const percent = gate['percent'];
67
- const unlocked = gate['unlocked'];
68
- if ('number' !== typeof percent || 'boolean' !== typeof unlocked)
69
- return undefined;
70
- const reason = gate['reason'];
71
- const prompt = instrumentation?.['prompt'];
72
- return {
73
- percent: Math.round(percent),
74
- unlocked,
75
- ...('string' === typeof reason ? { reason } : {}),
76
- ...('string' === typeof prompt ? { prompt } : {}),
77
- };
78
- }
79
43
  const row = (inner) => `<div class="reticle-harness-row">${inner}</div>`;
80
44
  const wrapRow = (inner) => `<div class="reticle-harness-row reticle-harness-row-wrap">${inner}</div>`;
81
45
  const said = (text) => `<span class="reticle-harness-said">${text}</span>`;
@@ -99,9 +63,6 @@ function creditsUsedRow(credits, planUrl) {
99
63
  function footState(s) {
100
64
  if (true === s.starting)
101
65
  return HARNESS_ROW_TEXT.STARTING;
102
- const gate = s.gate;
103
- if (gate !== undefined && !gate.unlocked && gate.reason !== undefined)
104
- return HARNESS_ROW_TEXT.footSetup(gate.percent);
105
66
  const config = s.config;
106
67
  if (config === undefined)
107
68
  return HARNESS_ROW_TEXT.FOOT_LINK;
@@ -120,8 +81,6 @@ function switchable(s) {
120
81
  const config = s.config;
121
82
  if (config === undefined)
122
83
  return false;
123
- if (s.gate !== undefined && !s.gate.unlocked && s.gate.reason !== undefined)
124
- return false;
125
84
  if (config.credits !== undefined && creditsSpent(config.credits))
126
85
  return false;
127
86
  return config.harnessEntitled && false !== config.providerReady;
@@ -146,11 +105,6 @@ export function harnessRowHtml(s) {
146
105
  return wrapRow(`${said(HARNESS_ROW_TEXT.SIGNED_OUT)}<button type="button" ${ACCOUNT_SIGNIN_ATTR} class="reticle-harness-link">${HARNESS_ROW_TEXT.SIGN_IN}</button>`);
147
106
  if (s.drive !== undefined && s.canDrive)
148
107
  return (runRow(said(HARNESS_ROW_TEXT.driving(s.startedAs === undefined ? undefined : personaLabel(s.startedAs), s.drive.steps)), STOP_BUTTON) + personaCustomHtml(s.pick, true));
149
- const gate = s.gate;
150
- if (gate !== undefined && !gate.unlocked && gate.reason !== undefined)
151
- return wrapRow(`${said(esc(gate.reason))}${gate.prompt === undefined
152
- ? ''
153
- : `<button type="button" ${HARNESS_COPY_PROMPT_ATTR} class="reticle-harness-link">${HARNESS_ROW_TEXT.COPY_PROMPT}</button>`}`);
154
108
  const config = s.config;
155
109
  if (config === undefined)
156
110
  return wrapRow(`${said(HARNESS_ROW_TEXT.UNLINKED)}<button type="button" ${HARNESS_LINK_ATTR} class="reticle-harness-run"${true === s.linking ? ' disabled' : ''}>${true === s.linking ? HARNESS_ROW_TEXT.LINKING : HARNESS_ROW_TEXT.LINK}</button>`);
@@ -161,11 +115,18 @@ export function harnessRowHtml(s) {
161
115
  if (false === config.providerReady)
162
116
  return row(`${said(HARNESS_ROW_TEXT.NO_PROVIDER)}${link(s.setupUrl, HARNESS_ROW_TEXT.SET_UP)}`);
163
117
  if (!config.harnessEnabled)
164
- return row(`${said(gate === undefined ? HARNESS_ROW_TEXT.OFF : HARNESS_ROW_TEXT.canSwitchOn(gate.percent))}<button type="button" ${HARNESS_SWITCH_ON_ATTR} class="reticle-harness-run">${HARNESS_ROW_TEXT.TURN_ON}</button>`);
118
+ return row(`${said(HARNESS_ROW_TEXT.OFF)}<button type="button" ${HARNESS_SWITCH_ON_ATTR} class="reticle-harness-run">${HARNESS_ROW_TEXT.TURN_ON}</button>`);
165
119
  if (!s.canDrive)
166
120
  return '';
167
121
  const starting = true === s.starting;
168
- return (runRow(personaPickHtml(s.pick, starting), `<button type="button" data-reticle-harness-run class="reticle-harness-run"${starting ? ' disabled' : ''}>${starting ? HARNESS_ROW_TEXT.STARTING : HARNESS_ROW_TEXT.RUN}</button>`) + personaCustomHtml(s.pick, starting));
122
+ return (runRow(personaPickHtml(s.pick, starting), `<button type="button" data-reticle-harness-run class="reticle-harness-run"${starting ? ' disabled' : ''}>${starting ? HARNESS_ROW_TEXT.STARTING : HARNESS_ROW_TEXT.RUN}</button>`) +
123
+ personaCustomHtml(s.pick, starting) +
124
+ (starting ? '' : lastRowHtml(s.last)));
125
+ }
126
+ function lastRowHtml(last) {
127
+ if (last === undefined || (last.said === undefined && last.runUrl === undefined))
128
+ return '';
129
+ return wrapRow(`${last.said === undefined ? '' : said(esc(last.said))}${last.runUrl === undefined ? '' : link(last.runUrl, HARNESS_ROW_TEXT.RESULT)}`);
169
130
  }
170
131
  export const HARNESS_ROW_CSS = `
171
132
  [data-reticle-chat-panel] .reticle-harness-spot{flex:none;display:flex;flex-direction:column;gap:4px;}
@@ -56,23 +56,6 @@ export const REPORT_CSS = `
56
56
  [${REPORT_PANEL_ATTR}] .reticle-report-coverage{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px;margin-bottom:12px;padding:8px 10px;border:1px solid var(--reticle-hud-border);border-radius:var(--reticle-hud-radius-sm,8px);}
57
57
  [${REPORT_PANEL_ATTR}] .reticle-report-coverage-value{font-size:18px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--reticle-hud-text);}
58
58
  [${REPORT_PANEL_ATTR}] .reticle-report-coverage-levels{display:flex;flex-wrap:wrap;gap:4px 10px;width:100%;font-size:11px;color:var(--reticle-faint);font-variant-numeric:tabular-nums;}
59
- [${REPORT_PANEL_ATTR}] .reticle-report-instrumentation{margin-bottom:12px;padding:10px;border:1px solid var(--reticle-hud-border);border-radius:var(--reticle-hud-radius-md);}
60
- [${REPORT_PANEL_ATTR}] .reticle-report-instrumentation-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;}
61
- [${REPORT_PANEL_ATTR}] .reticle-report-instrumentation-head .reticle-report-section{margin-bottom:0;}
62
- [${REPORT_PANEL_ATTR}] .reticle-report-instrumentation-value{font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--reticle-hud-text);}
63
- [${REPORT_PANEL_ATTR}] .reticle-report-caps{display:grid;grid-template-columns:1fr 1fr;gap:4px 10px;margin:8px 0 0;padding:0;list-style:none;}
64
- [${REPORT_PANEL_ATTR}] .reticle-report-cap{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 6px;min-width:0;font-size:11px;line-height:1.4;color:var(--reticle-muted);}
65
- [${REPORT_PANEL_ATTR}] .reticle-report-cap-mark{flex:none;width:10px;text-align:center;}
66
- [${REPORT_PANEL_ATTR}] .reticle-report-cap-name{flex:1;min-width:0;}
67
- [${REPORT_PANEL_ATTR}] .reticle-report-cap[data-state="seen"] .reticle-report-cap-mark{color:#86efac;}
68
- [${REPORT_PANEL_ATTR}] .reticle-report-cap[data-state="missing"]{grid-column:1/-1;color:var(--reticle-hud-text);}
69
- [${REPORT_PANEL_ATTR}] .reticle-report-cap[data-state="missing"] .reticle-report-cap-mark{color:#fca5a5;}
70
- [${REPORT_PANEL_ATTR}] .reticle-report-cap[data-state="unseen"]{color:var(--reticle-faint);}
71
- [${REPORT_PANEL_ATTR}] .reticle-report-cap-cost{flex-basis:100%;padding-left:16px;color:var(--reticle-faint);}
72
- [${REPORT_PANEL_ATTR}] .reticle-report-caps-note{display:block;margin-top:6px;color:var(--reticle-faint);font-size:11px;}
73
- [${REPORT_PANEL_ATTR}] .reticle-report-copy-prompt{display:block;width:100%;margin-top:10px;padding:6px 10px;border:1px solid color-mix(in srgb,var(--reticle-hud-brand) 50%,transparent);
74
- border-radius:var(--reticle-hud-radius-sm);background:var(--reticle-hud-brand-soft);color:var(--reticle-hud-brand);font:inherit;font-size:12px;font-weight:600;cursor:pointer;}
75
- [${REPORT_PANEL_ATTR}] .reticle-report-copy-prompt:hover{filter:brightness(1.15);}
76
59
  [${REPORT_PANEL_ATTR}] .reticle-report-verdict{
77
60
  flex:1;padding:5px 8px;border-radius:8px;font-size:11px;text-align:center;
78
61
  background:rgba(255,255,255,.05);color:var(--reticle-muted);}
@@ -1,7 +1,6 @@
1
1
  import { type AccountState, type ImpactScope, type ImpactSnapshot } from '@reticlehq/core';
2
2
  export declare function reportPanelHtml(): string;
3
- export declare function instrumentationHtml(instrumentation: Readonly<Record<string, unknown>> | undefined): string;
4
- export declare function reportBodyHtml(scope: ImpactScope, dashboardUrl?: string, account?: AccountState, projectName?: string, coverage?: Readonly<Record<string, number>>, sync?: Readonly<Record<string, unknown>>, instrumentation?: Readonly<Record<string, unknown>>): string;
3
+ export declare function reportBodyHtml(scope: ImpactScope, dashboardUrl?: string, account?: AccountState, projectName?: string, coverage?: Readonly<Record<string, number>>, sync?: Readonly<Record<string, unknown>>): string;
5
4
  interface ReportHost {
6
5
  onBeforeOpen?: () => void;
7
6
  onSyncNow?: () => void;
@@ -4,7 +4,7 @@ import { HUD_SURFACE_CLASS } from './chrome/presenter-hud-chrome.js';
4
4
  import { esc, isSafeDashboardUrl } from './chrome/presenter-safe-html.js';
5
5
  import { ACCOUNT_SIGNIN_ATTR, ACCOUNT_TEXT, SYNC_BTN_ATTR, accountControlHtml, syncButtonHtml, } from './presenter-account.js';
6
6
  import { REPORT_PANEL_ATTR, REPORT_ATTR, REPORT_CLOSE_ATTR } from './presenter-config.js';
7
- import { REPORT_LINKS, REPORT_TEXT, buildLinkedInShareUrl, buildReferralText, buildShareText, buildXShareUrl, compactDuration, compactNumber, COVERAGE_LEVELS, CAPABILITY_WORDS, } from './chrome/presenter-report-copy.js';
7
+ import { REPORT_LINKS, REPORT_TEXT, buildLinkedInShareUrl, buildReferralText, buildShareText, buildXShareUrl, compactDuration, compactNumber, COVERAGE_LEVELS, } from './chrome/presenter-report-copy.js';
8
8
  const SCOPE_ATTR = 'data-reticle-report-scope';
9
9
  const SCOPE = { PROJECT: 'project', MACHINE: 'machine' };
10
10
  const SHARE_X_ATTR = 'data-reticle-share-x';
@@ -119,49 +119,6 @@ function syncStatusHtml(sync) {
119
119
  : '';
120
120
  return `<span class="reticle-sync-status" data-reticle-sync-status="${esc(String(status))}" title="${esc(said)}">${label}</span>${seeRun}`;
121
121
  }
122
- const capabilityWords = (name) => 'string' === typeof name ? esc(CAPABILITY_WORDS[name] ?? name) : undefined;
123
- function capabilityItem(state, name, cost = '') {
124
- const mark = 'seen' === state ? '✓' : 'missing' === state ? '✕' : '○';
125
- const why = '' === cost ? '' : `<span class="reticle-report-cap-cost">${cost}</span>`;
126
- return `<li class="reticle-report-cap" data-state="${state}"><span class="reticle-report-cap-mark" aria-hidden="true">${mark}</span><span class="reticle-report-cap-name">${name}</span>${why}</li>`;
127
- }
128
- export function instrumentationHtml(instrumentation) {
129
- if (instrumentation === undefined)
130
- return '';
131
- const covered = instrumentation['covered'];
132
- const total = instrumentation['total'];
133
- if ('number' !== typeof covered || 'number' !== typeof total)
134
- return '';
135
- const list = (key) => {
136
- const value = instrumentation[key];
137
- return Array.isArray(value) ? value : [];
138
- };
139
- const seen = list('seen').flatMap((n) => {
140
- const name = capabilityWords(n);
141
- return name === undefined ? [] : [capabilityItem('seen', name)];
142
- });
143
- const missing = list('missing').flatMap((m) => {
144
- if ('object' !== typeof m || null === m)
145
- return [];
146
- const gap = m;
147
- const name = capabilityWords(gap['capability']);
148
- const cost = 'string' === typeof gap['cost'] ? esc(gap['cost']) : '';
149
- return name === undefined ? [] : [capabilityItem('missing', name, cost)];
150
- });
151
- const unseen = list('notSeenYet').flatMap((n) => {
152
- const name = capabilityWords(n);
153
- return name === undefined ? [] : [capabilityItem('unseen', name)];
154
- });
155
- const items = [...missing, ...seen, ...unseen];
156
- const caps = 0 === items.length
157
- ? ''
158
- : `<ul class="reticle-report-caps">${items.join('')}</ul>${0 === unseen.length ? '' : `<span class="reticle-report-caps-note">○ ${REPORT_TEXT.NOT_SEEN_YET}</span>`}`;
159
- const copy = 'string' === typeof instrumentation['prompt']
160
- ? `<button type="button" class="reticle-report-copy-prompt" ${COPY_PROMPT_ATTR}>${REPORT_TEXT.COPY_PROMPT}</button>`
161
- : '';
162
- return `<div class="reticle-report-instrumentation" title="${REPORT_TEXT.INSTRUMENTATION_HELP}"><div class="reticle-report-instrumentation-head"><span class="reticle-report-section">${REPORT_TEXT.INSTRUMENTATION}</span><span class="reticle-report-instrumentation-value">${REPORT_TEXT.covered(Math.round(covered), Math.round(total))}</span></div>${caps}${copy}</div>`;
163
- }
164
- const COPY_PROMPT_ATTR = 'data-reticle-copy-prompt';
165
122
  function coverageHtml(coverage) {
166
123
  if (coverage === undefined)
167
124
  return '';
@@ -175,7 +132,7 @@ function coverageHtml(coverage) {
175
132
  .join('');
176
133
  return `<div class="reticle-report-coverage" title="${REPORT_TEXT.COVERAGE_HELP}"><span class="reticle-report-section">${REPORT_TEXT.COVERAGE}</span><span class="reticle-report-coverage-value">${head}</span><div class="reticle-report-coverage-levels">${rows}</div></div>`;
177
134
  }
178
- export function reportBodyHtml(scope, dashboardUrl, account, projectName, coverage, sync, instrumentation) {
135
+ export function reportBodyHtml(scope, dashboardUrl, account, projectName, coverage, sync) {
179
136
  const c = scope.counts;
180
137
  if (0 === c.calls)
181
138
  return `<p class="reticle-report-empty">${REPORT_TEXT.EMPTY}</p>`;
@@ -199,7 +156,7 @@ export function reportBodyHtml(scope, dashboardUrl, account, projectName, covera
199
156
  card(compactDuration(scope.savings.minutes.value * 60_000), REPORT_TEXT.SAVED_MINUTES, scope.savings.minutes.basis),
200
157
  ].join('');
201
158
  const identity = `<div class="reticle-report-identity">${accountControlHtml(account, { dashboardUrl, projectName, verdicts: c.verdicts, defects: c.failed })}${syncButtonHtml(dashboardUrl)}${syncStatusHtml(sync)}</div>`;
202
- return `<div class="reticle-report-top">${streak}${identity}</div>${hero}${verdicts}${instrumentationHtml(instrumentation)}${coverageHtml(coverage)}<div class="reticle-report-grid">${cards}</div>${defects(scope, dashboardUrl)}${chart(scope)}${localOnly(scope, dashboardUrl, account)}`;
159
+ return `<div class="reticle-report-top">${streak}${identity}</div>${hero}${verdicts}${coverageHtml(coverage)}<div class="reticle-report-grid">${cards}</div>${defects(scope, dashboardUrl)}${chart(scope)}${localOnly(scope, dashboardUrl, account)}`;
203
160
  }
204
161
  function localOnly(scope, dashboardUrl, account) {
205
162
  if (dashboardUrl !== undefined)
@@ -271,13 +228,6 @@ export class PresenterReport {
271
228
  void this.#copy(ACCOUNT_TEXT.SIGNIN_COMMAND, signin);
272
229
  return;
273
230
  }
274
- const copyPrompt = target.closest(`[${COPY_PROMPT_ATTR}]`);
275
- const prompt = this.#snapshot?.instrumentation?.['prompt'];
276
- if (copyPrompt !== null && 'string' === typeof prompt) {
277
- e.stopPropagation();
278
- void this.#copy(prompt, copyPrompt);
279
- return;
280
- }
281
231
  const sync = target.closest(`[${SYNC_BTN_ATTR}]`);
282
232
  if (sync !== null) {
283
233
  e.stopPropagation();
@@ -340,7 +290,7 @@ export class PresenterReport {
340
290
  this.#body.innerHTML =
341
291
  scope === undefined
342
292
  ? `<p class="reticle-report-empty">${REPORT_TEXT.EMPTY}</p>`
343
- : reportBodyHtml(scope, this.#snapshot?.dashboardUrl, this.#snapshot?.account, this.#snapshot?.projectName, this.#global ? undefined : this.#snapshot?.coverage, this.#global ? undefined : this.#snapshot?.sync, this.#global ? undefined : this.#snapshot?.instrumentation);
293
+ : reportBodyHtml(scope, this.#snapshot?.dashboardUrl, this.#snapshot?.account, this.#snapshot?.projectName, this.#global ? undefined : this.#snapshot?.coverage, this.#global ? undefined : this.#snapshot?.sync);
344
294
  }
345
295
  #openShare(url) {
346
296
  window.open(url, '_blank', 'noopener,noreferrer');
@@ -1,4 +1,5 @@
1
1
  import { SessionState } from '@reticlehq/core';
2
+ import { pageHref } from '../security/page-location.js';
2
3
  import { LOG_KIND, LOG_RESULT } from './chrome/presenter-log.js';
3
4
  import { getCapabilities } from '../registry/capabilities.js';
4
5
  export function buildRunState(input) {
@@ -20,7 +21,7 @@ export function buildRunState(input) {
20
21
  }
21
22
  return {
22
23
  session: input.sessionId,
23
- url: 'undefined' === typeof location ? '' : location.href,
24
+ url: 'undefined' === typeof location ? '' : pageHref(),
24
25
  state: input.state,
25
26
  startedMs: start,
26
27
  durationMs: Math.max(0, (input.endMs ?? input.now) - start),
@@ -1,5 +1,4 @@
1
1
  import type { HarnessConfig } from '@reticlehq/core';
2
- import type { HarnessGateView } from './presenter-harness-row.js';
3
2
  import { SETTINGS_CSS } from './presenter-settings-styles.js';
4
3
  import { type Credits } from '@reticlehq/core/hud';
5
4
  import type { AccountState } from '@reticlehq/core';
@@ -45,7 +44,7 @@ export declare function loadPresenterSettings(): PresenterSettings;
45
44
  export declare const SETTINGS_ACCOUNT_ATTR = "data-reticle-settings-account";
46
45
  export declare const HARNESS_LOCKED_HELP = "The Harness is not available to this workspace right now: see Plan in your Reticle dashboard.";
47
46
  export declare function creditsLeft(credits: Credits | undefined): string;
48
- export declare function paintHarnessRow(root: ParentNode, config: HarnessConfig | undefined, gate?: HarnessGateView): void;
47
+ export declare function paintHarnessRow(root: ParentNode, config: HarnessConfig | undefined): void;
49
48
  export declare function paintSettingsAccount(root: HTMLElement, account: AccountState | undefined, dashboardUrl: string | undefined, details?: AccountDetails): void;
50
49
  export declare function paintSdkVersion(root: ParentNode, version: string | undefined): void;
51
50
  export declare function settingsPanelHtml(): string;
@@ -63,7 +62,7 @@ export declare class PresenterSettingsPanel {
63
62
  constructor(host?: SettingsHost);
64
63
  contains(node: Node): boolean;
65
64
  mount(root: HTMLElement): void;
66
- paintHarness(config: HarnessConfig | undefined, gate?: HarnessGateView): void;
65
+ paintHarness(config: HarnessConfig | undefined): void;
67
66
  teardown(): void;
68
67
  isOpen(): boolean;
69
68
  open(): void;