@reticlehq/browser 3.4.0 → 3.6.0

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 (89) hide show
  1. package/dist/actions/actions-dom.js +44 -43
  2. package/dist/actions/actions-press.d.ts +10 -4
  3. package/dist/actions/actions-press.js +108 -17
  4. package/dist/actions/actions.d.ts +2 -1
  5. package/dist/actions/actions.js +25 -26
  6. package/dist/actions/danger-context.js +1 -1
  7. package/dist/commands/commands.js +2 -6
  8. package/dist/connect-options.d.ts +1 -0
  9. package/dist/dom/a11y.js +43 -11
  10. package/dist/dom/addressing/refs.js +2 -1
  11. package/dist/dom/addressing/testid-attr.d.ts +4 -0
  12. package/dist/dom/addressing/testid-attr.js +14 -0
  13. package/dist/dom/occlusion.js +5 -1
  14. package/dist/dom/query.d.ts +1 -0
  15. package/dist/dom/query.js +42 -15
  16. package/dist/dom/snapshot.js +1 -0
  17. package/dist/observers/departure.js +51 -9
  18. package/dist/observers/dom.js +3 -2
  19. package/dist/observers/field.js +5 -3
  20. package/dist/observers/health.js +63 -2
  21. package/dist/observers/network-stream.d.ts +1 -1
  22. package/dist/observers/network-stream.js +3 -3
  23. package/dist/observers/network.js +1 -1
  24. package/dist/observers/storage.js +6 -1
  25. package/dist/presenter/carousel/carousel.d.ts +5 -2
  26. package/dist/presenter/carousel/carousel.js +34 -7
  27. package/dist/presenter/carousel/offer-card.d.ts +2 -2
  28. package/dist/presenter/carousel/offer-card.js +2 -1
  29. package/dist/presenter/carousel/panel-slides.d.ts +4 -3
  30. package/dist/presenter/carousel/panel-slides.js +43 -6
  31. package/dist/presenter/carousel/talk-card.d.ts +1 -1
  32. package/dist/presenter/chrome/log-kinds.d.ts +5 -0
  33. package/dist/presenter/chrome/log-kinds.js +1 -0
  34. package/dist/presenter/chrome/log-memory.d.ts +12 -0
  35. package/dist/presenter/chrome/log-memory.js +39 -0
  36. package/dist/presenter/chrome/presenter-hud-chrome.d.ts +1 -0
  37. package/dist/presenter/chrome/presenter-hud-chrome.js +7 -1
  38. package/dist/presenter/chrome/presenter-log.d.ts +5 -4
  39. package/dist/presenter/chrome/presenter-log.js +55 -5
  40. package/dist/presenter/chrome/presenter-report-copy.d.ts +11 -1
  41. package/dist/presenter/chrome/presenter-report-copy.js +14 -1
  42. package/dist/presenter/hud-telemetry.js +31 -2
  43. package/dist/presenter/icons/presenter-heroicons-data.d.ts +1 -0
  44. package/dist/presenter/icons/presenter-heroicons-data.js +4 -3
  45. package/dist/presenter/icons/presenter-icons.d.ts +2 -0
  46. package/dist/presenter/icons/presenter-icons.js +2 -0
  47. package/dist/presenter/presenter-account.d.ts +5 -4
  48. package/dist/presenter/presenter-account.js +23 -10
  49. package/dist/presenter/presenter-chat-views.d.ts +21 -0
  50. package/dist/presenter/presenter-chat-views.js +382 -0
  51. package/dist/presenter/presenter-config.d.ts +3 -2
  52. package/dist/presenter/presenter-config.js +4 -3
  53. package/dist/presenter/presenter-controls.d.ts +4 -2
  54. package/dist/presenter/presenter-controls.js +231 -51
  55. package/dist/presenter/presenter-design-tokens.d.ts +1 -0
  56. package/dist/presenter/presenter-design-tokens.js +34 -0
  57. package/dist/presenter/presenter-dock-layout.js +1 -1
  58. package/dist/presenter/presenter-frame.d.ts +12 -0
  59. package/dist/presenter/presenter-frame.js +189 -0
  60. package/dist/presenter/presenter-plan.d.ts +10 -0
  61. package/dist/presenter/presenter-plan.js +185 -0
  62. package/dist/presenter/presenter-report-styles.js +7 -0
  63. package/dist/presenter/presenter-report.d.ts +1 -1
  64. package/dist/presenter/presenter-report.js +53 -16
  65. package/dist/presenter/presenter-settings-styles.js +10 -0
  66. package/dist/presenter/presenter-settings.d.ts +5 -0
  67. package/dist/presenter/presenter-settings.js +71 -11
  68. package/dist/presenter/presenter-shell-styles.js +39 -42
  69. package/dist/presenter/presenter-shell.d.ts +8 -1
  70. package/dist/presenter/presenter-shell.js +124 -72
  71. package/dist/presenter/presenter-styles.js +9 -1
  72. package/dist/presenter/presenter.d.ts +4 -3
  73. package/dist/presenter/presenter.js +101 -13
  74. package/dist/presenter/tour/tour.d.ts +4 -1
  75. package/dist/presenter/tour/tour.js +6 -4
  76. package/dist/recorder/recorder.js +2 -2
  77. package/dist/registry/auto-testids.js +3 -4
  78. package/dist/registry/declared-platform.js +2 -0
  79. package/dist/reticle-inject.js +880 -513
  80. package/dist/reticle.d.ts +10 -1
  81. package/dist/reticle.js +73 -9
  82. package/dist/review/annotator-styles.d.ts +1 -1
  83. package/dist/review/annotator.d.ts +7 -0
  84. package/dist/review/annotator.js +20 -2
  85. package/dist/review/mark-anchor.js +2 -2
  86. package/dist/session-continuity.js +2 -1
  87. package/dist/storage-keys.d.ts +14 -0
  88. package/dist/storage-keys.js +17 -0
  89. package/package.json +3 -2
@@ -1,10 +1,47 @@
1
1
  import { offerHtml } from './offer-card.js';
2
- import { talkCardHtml } from './talk-card.js';
3
- export const SLIDE_ID = { HARNESS: 'harness', FOUNDERS: 'founders' };
4
- export function panelSlides(offer, offerDeclined) {
5
- const harness = offerHtml(offer, offerDeclined);
2
+ import { HudNoticeSchema } from '@reticlehq/core/hud';
3
+ import { esc } from '../chrome/presenter-safe-html.js';
4
+ import { DEFAULT_PLATFORM_URL } from '@reticlehq/core';
5
+ const HARNESS_PATH = '/settings?group=billing';
6
+ export const SLIDE_ID = {
7
+ HARNESS: 'harness-journeys',
8
+ REPLAY: 'replay-confidence',
9
+ OFFER: 'harness-offer',
10
+ };
11
+ const valueSlides = (base) => [
12
+ {
13
+ id: SLIDE_ID.HARNESS,
14
+ html: `<div class="reticle-promo-copy"><span class="reticle-promo-kicker">RETICLE HARNESS</span><strong class="reticle-promo-title">Let Reticle drive your app for you</strong><span class="reticle-promo-detail">Describe a user; it drives the journey and saves it to replay.</span><a data-reticle-promo-link class="reticle-promo-link" href="${base}${HARNESS_PATH}" target="_blank" rel="noopener noreferrer">Explore →</a></div>`,
15
+ },
16
+ {
17
+ id: SLIDE_ID.REPLAY,
18
+ html: `<div class="reticle-promo-copy"><span class="reticle-promo-kicker">FROM RUN TO REGRESSION</span><strong class="reticle-promo-title">Keep every journey replayable</strong><span class="reticle-promo-detail">Catch what changes before users do.</span><a data-reticle-promo-link class="reticle-promo-link" href="${base}${HARNESS_PATH}" target="_blank" rel="noopener noreferrer">See how →</a></div>`,
19
+ },
20
+ ];
21
+ const NOTICE_SLIDE_PREFIX = 'notice-';
22
+ function noticeSlide(notice) {
23
+ const kicker = notice.kicker === undefined
24
+ ? ''
25
+ : `<span class="reticle-promo-kicker">${esc(notice.kicker)}</span>`;
26
+ const detail = notice.detail === undefined
27
+ ? ''
28
+ : `<span class="reticle-promo-detail">${esc(notice.detail)}</span>`;
29
+ const link = notice.cta === undefined
30
+ ? ''
31
+ : `<a data-reticle-promo-link class="reticle-promo-link" href="${esc(notice.cta.url)}" target="_blank" rel="noopener noreferrer">${esc(notice.cta.label)} →</a>`;
32
+ return {
33
+ id: `${NOTICE_SLIDE_PREFIX}${notice.id}`,
34
+ html: `<div class="reticle-promo-copy">${kicker}<strong class="reticle-promo-title">${esc(notice.title)}</strong>${detail}${link}</div>`,
35
+ };
36
+ }
37
+ export function panelSlides(offer, offerDeclined, notices = [], base = DEFAULT_PLATFORM_URL) {
38
+ const harnessOffer = offerHtml(offer, offerDeclined);
39
+ const valid = notices.flatMap((n) => {
40
+ const parsed = HudNoticeSchema.safeParse(n);
41
+ return parsed.success ? [parsed.data] : [];
42
+ });
6
43
  return [
7
- ...('' === harness ? [] : [{ id: SLIDE_ID.HARNESS, html: harness }]),
8
- { id: SLIDE_ID.FOUNDERS, html: talkCardHtml() },
44
+ ...('' === harnessOffer ? [] : [{ id: SLIDE_ID.OFFER, html: harnessOffer }]),
45
+ ...(0 < valid.length ? valid.map(noticeSlide) : valueSlides(base)),
9
46
  ];
10
47
  }
@@ -5,4 +5,4 @@ export declare const TALK_TEXT: {
5
5
  readonly BOOK: "Book a call";
6
6
  };
7
7
  export declare function talkCardHtml(): string;
8
- export declare const TALK_CSS = "\n.reticle-talk-title{display:block;font-weight:600;font-size:12px;padding-right:18px;}\n.reticle-talk-body{margin:6px 0 8px;font-size:11px;line-height:1.45;opacity:.8;}\n.reticle-talk-book{display:inline-block;font-size:11px;font-weight:600;padding:4px 10px;border-radius:6px;background:var(--reticle-accent,#4f7cff);color:#fff;text-decoration:none;}\n";
8
+ export declare const TALK_CSS: string;
@@ -10,3 +10,8 @@ export declare const LOG_RESULT: {
10
10
  readonly FAIL: "fail";
11
11
  };
12
12
  export type LogResult = (typeof LOG_RESULT)[keyof typeof LOG_RESULT];
13
+ export declare const LOG_ACTOR: {
14
+ readonly AGENT: "agent";
15
+ readonly HARNESS: "harness";
16
+ };
17
+ export type LogActor = (typeof LOG_ACTOR)[keyof typeof LOG_ACTOR];
@@ -5,3 +5,4 @@ export const LOG_KIND = {
5
5
  HUMAN: 'human',
6
6
  };
7
7
  export const LOG_RESULT = { PASS: 'pass', FAIL: 'fail' };
8
+ export const LOG_ACTOR = { AGENT: 'agent', HARNESS: 'harness' };
@@ -0,0 +1,12 @@
1
+ import type { LogActor, LogKind, LogResult } from './presenter-log.js';
2
+ export interface RememberedRow {
3
+ kind: LogKind;
4
+ text: string;
5
+ ts: string;
6
+ at: number;
7
+ actor?: LogActor;
8
+ result?: LogResult;
9
+ }
10
+ export declare function readRememberedLog(): RememberedRow[];
11
+ export declare function rememberLog(rows: readonly RememberedRow[]): void;
12
+ export declare function claimLog(owner: string | undefined): boolean;
@@ -0,0 +1,39 @@
1
+ import { ReticleStorageKey } from '../../storage-keys.js';
2
+ const LOG_STORAGE_KEY = ReticleStorageKey.PRESENTER_LOG;
3
+ export function readRememberedLog() {
4
+ try {
5
+ const raw = JSON.parse(globalThis.sessionStorage.getItem(LOG_STORAGE_KEY) ?? '[]');
6
+ return Array.isArray(raw)
7
+ ? raw.filter((row) => 'object' === typeof row &&
8
+ null !== row &&
9
+ 'string' === typeof row.text &&
10
+ 'string' === typeof row.kind &&
11
+ 'string' === typeof row.ts &&
12
+ 'number' === typeof row.at)
13
+ : [];
14
+ }
15
+ catch {
16
+ return [];
17
+ }
18
+ }
19
+ export function rememberLog(rows) {
20
+ try {
21
+ globalThis.sessionStorage.setItem(LOG_STORAGE_KEY, JSON.stringify(rows));
22
+ }
23
+ catch {
24
+ }
25
+ }
26
+ export function claimLog(owner) {
27
+ try {
28
+ const now = owner ?? '';
29
+ const before = globalThis.sessionStorage.getItem(ReticleStorageKey.PRESENTER_LOG_OWNER);
30
+ globalThis.sessionStorage.setItem(ReticleStorageKey.PRESENTER_LOG_OWNER, now);
31
+ if (null === before || before === now)
32
+ return false;
33
+ globalThis.sessionStorage.removeItem(LOG_STORAGE_KEY);
34
+ return true;
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
@@ -2,6 +2,7 @@ export declare const HUD_SURFACE_CLASS = "reticle-hud-surface";
2
2
  export declare const HUD_SURFACE_FILL: string;
3
3
  export declare const HUD_SURFACE_PAINT: string;
4
4
  export declare const HUD_DROP_SHADOW: string;
5
+ export declare const HUD_GLASS_PAINT: string;
5
6
  export declare const HUD_CHROME_CSS: string;
6
7
  export declare const HUD_LOG_WELL_CLASS = "reticle-hud-log-well";
7
8
  export declare const HUD_LOG_WELL_CSS: string;
@@ -2,6 +2,12 @@ export const HUD_SURFACE_CLASS = 'reticle-hud-surface';
2
2
  export const HUD_SURFACE_FILL = `linear-gradient(165deg,#121218 0%,#09090c 42%,#000 100%)`;
3
3
  export const HUD_SURFACE_PAINT = `background:${HUD_SURFACE_FILL};box-shadow:inset 0 1px 0 rgba(255,255,255,.09),0 0 0 1px rgba(255,255,255,.09);`;
4
4
  export const HUD_DROP_SHADOW = '0 16px 40px rgba(0,0,0,.58),0 0 0 1px rgba(255,255,255,.08)';
5
+ export const HUD_GLASS_PAINT = [
6
+ 'background:radial-gradient(130% 80% at 50% 0%,color-mix(in srgb,var(--reticle-c-active) 20%,transparent),transparent 62%),',
7
+ 'linear-gradient(180deg,#121a2e,#080b14);',
8
+ 'border:1px solid color-mix(in srgb,var(--reticle-c-active) 30%,rgba(255,255,255,.1));',
9
+ `box-shadow:${HUD_DROP_SHADOW},0 0 64px -12px color-mix(in srgb,var(--reticle-c-active) 75%,transparent);`,
10
+ ].join('');
5
11
  export const HUD_CHROME_CSS = `
6
12
  .${HUD_SURFACE_CLASS}{
7
13
  position:relative;overflow:hidden;
@@ -25,7 +31,7 @@ export const HUD_LOG_WELL_CSS = `
25
31
  as tall as its rows, which left the empty-state line floating near the top of an otherwise
26
32
  empty panel instead of centred in it. */
27
33
  position:relative;display:flex;flex-direction:column;
28
- flex:1 1 auto;height:210px;min-height:96px;max-height:210px;overflow:hidden;
34
+ flex:1 1 auto;height:240px;min-height:120px;max-height:300px;overflow:hidden;
29
35
  contain:layout style paint;
30
36
  margin:0 6px;border-radius:12px;background:transparent;}
31
37
  .${HUD_LOG_WELL_CLASS} > *{position:relative;z-index:1;}`;
@@ -1,11 +1,12 @@
1
1
  import { PresenterMode } from '@reticlehq/core';
2
- import { LOG_KIND, LOG_RESULT, type LogKind, type LogResult } from './log-kinds.js';
3
- export { LOG_KIND, LOG_RESULT };
4
- export type { LogKind, LogResult };
2
+ import { LOG_ACTOR, LOG_KIND, LOG_RESULT, type LogActor, type LogKind, type LogResult } from './log-kinds.js';
3
+ export { LOG_ACTOR, LOG_KIND, LOG_RESULT };
4
+ export type { LogActor, LogKind, LogResult };
5
5
  export declare const CHIP_LABEL: Record<PresenterMode, string>;
6
6
  export declare const DATA_RETICLE_LOG = "data-reticle-log";
7
7
  export declare const LOG_TIME_ATTR = "data-reticle-log-time";
8
8
  export declare const LOG_CSS: string;
9
+ export declare const LOG_SCROLLABLE_ATTR = "data-reticle-log-scrollable";
9
10
  export declare function settleLogAtLatest(container: HTMLElement): void;
10
11
  export interface LogHandle {
11
12
  result(r: LogResult): void;
@@ -15,4 +16,4 @@ export declare function clearLogRows(container: HTMLElement): void;
15
16
  export declare function clampLogMax(n: number | undefined): number;
16
17
  export declare function humanDuration(ms: number): string;
17
18
  export declare function formatElapsed(ms: number): string;
18
- export declare function appendLogRow(container: HTMLElement, kind: LogKind, text: string, ts: string, logMax: number): LogHandle;
19
+ export declare function appendLogRow(container: HTMLElement, kind: LogKind, text: string, ts: string, logMax: number, actor?: LogActor): LogHandle;
@@ -1,9 +1,9 @@
1
1
  import { PresenterMode } from '@reticlehq/core';
2
- import { LOG_KIND, LOG_RESULT } from './log-kinds.js';
2
+ import { LOG_ACTOR, LOG_KIND, LOG_RESULT, } from './log-kinds.js';
3
3
  import { nativeSetTimeout } from '../../timers/native/native-timers.js';
4
4
  import { PresenterIcon, PRESENTER_ICON_SIZE, hiIcon, } from '../icons/presenter-icons.js';
5
5
  const DEFAULT_LOG_MAX = 50;
6
- export { LOG_KIND, LOG_RESULT };
6
+ export { LOG_ACTOR, LOG_KIND, LOG_RESULT };
7
7
  const LOG_CHIP = { read: 'READ', act: 'ACT', narration: '', human: '' };
8
8
  const LOG_CHIP_ICON = {
9
9
  read: PresenterIcon.VIEW,
@@ -20,7 +20,15 @@ const LOG_CHIP_MODE = {
20
20
  narration: PresenterMode.IDLE,
21
21
  human: PresenterMode.IDLE,
22
22
  };
23
- const RESULT_GLYPH = { pass: '', fail: 'Fail' };
23
+ const RESULT_GLYPH = { pass: '✓', fail: 'Fail' };
24
+ const HANDOVER_TEXT = {
25
+ agent: 'Your agent is driving',
26
+ harness: 'Reticle Harness is driving',
27
+ };
28
+ const LAST_ACTOR_ATTR = 'data-reticle-log-actor';
29
+ const DATA_ACTOR = 'data-actor';
30
+ const DATA_STATE = 'data-state';
31
+ const HANDOVER_KIND = 'handover';
24
32
  const RESULT_CLASS = { pass: 'reticle-pass', fail: 'reticle-fail' };
25
33
  export const DATA_RETICLE_LOG = 'data-reticle-log';
26
34
  const DATA_RETICLE_LOG_ROW = 'data-reticle-log-row';
@@ -69,10 +77,34 @@ export const LOG_CSS = `
69
77
  padding:8px 12px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);
70
78
  border-radius:16px 16px 4px 16px;box-shadow:inset 0 1px 0 rgba(255,255,255,.08);}
71
79
  [data-reticle-log-row][data-kind="human"] .reticle-log-text{color:var(--reticle-fg);font-size:12px;line-height:1.45;}
80
+ /* Rows arrive, rather than appear: the person watching should see the log move. */
81
+ [data-reticle-log-row]{animation:reticle-row-in .22s var(--reticle-hud-ease,ease) both;}
82
+ @keyframes reticle-row-in{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
83
+ @media (prefers-reduced-motion:reduce){[data-reticle-log-row]{animation:none;}}
84
+ /* The step in flight pulses until its verdict lands; then it says how it ended. */
85
+ [data-reticle-log-row][data-state="running"] .reticle-res{display:inline-block;width:6px;height:6px;margin-top:5px;
86
+ border-radius:50%;background:var(--reticle-c-active);opacity:1;animation:reticle-row-pulse 1s ease-in-out infinite;}
87
+ @keyframes reticle-row-pulse{0%,100%{opacity:.35;transform:scale(.8)}50%{opacity:1;transform:scale(1)}}
88
+ [data-reticle-log] .reticle-res.reticle-pass{display:inline;color:#4ade80;font-size:10px;opacity:.9;}
89
+ [data-reticle-log] .reticle-res.reticle-fail{color:#fca5a5;background:rgba(239,68,68,.16);border-radius:999px;padding:1px 6px;font-size:8px;opacity:1;}
90
+ /* The Harness's rows wear its own colour, so two drivers never read as one. */
91
+ [data-reticle-log-row][data-actor="harness"]{--reticle-row-accent:#a78bfa;}
92
+ [data-reticle-log-row][data-actor="harness"] .reticle-chip{color:#a78bfa;}
93
+ [data-reticle-log-row][data-actor="harness"]:not([data-kind="handover"]){box-shadow:inset 2px 0 0 color-mix(in srgb,#a78bfa 55%,transparent);padding-left:8px;}
94
+ [data-reticle-log-row][data-kind="handover"]{align-items:center;gap:8px;margin:8px 0 4px;padding:0;
95
+ font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--reticle-row-accent,var(--reticle-c-active));}
96
+ [data-reticle-log-row][data-kind="handover"]::before,[data-reticle-log-row][data-kind="handover"]::after{
97
+ content:"";flex:1;height:1px;background:color-mix(in srgb,var(--reticle-row-accent,var(--reticle-c-active)) 40%,transparent);}
98
+ [data-reticle-log-row][data-kind="handover"] .reticle-log-text{flex:none;color:inherit;}
99
+ /* What the Harness or the daemon says about a drive reads as a notice, not an aside. */
100
+ [data-reticle-log-row][data-kind="narration"]{font-style:normal;color:var(--reticle-fg);margin:4px 0;padding:7px 10px;
101
+ border-radius:10px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);}
72
102
  `;
73
103
  function scrollLogToLatest(container) {
74
104
  container.scrollTop = container.scrollHeight;
105
+ container.toggleAttribute(LOG_SCROLLABLE_ATTR, container.scrollHeight > container.clientHeight + 1);
75
106
  }
107
+ export const LOG_SCROLLABLE_ATTR = 'data-reticle-log-scrollable';
76
108
  export function settleLogAtLatest(container) {
77
109
  scrollLogToLatest(container);
78
110
  requestAnimationFrame(() => {
@@ -111,10 +143,27 @@ export function humanDuration(ms) {
111
143
  export function formatElapsed(ms) {
112
144
  return humanDuration(ms);
113
145
  }
114
- export function appendLogRow(container, kind, text, ts, logMax) {
146
+ export function appendLogRow(container, kind, text, ts, logMax, actor = LOG_ACTOR.AGENT) {
147
+ const driven = kind === LOG_KIND.ACT || kind === LOG_KIND.READ;
148
+ if (driven && (container.getAttribute(LAST_ACTOR_ATTR) ?? LOG_ACTOR.AGENT) !== actor) {
149
+ const divider = document.createElement('div');
150
+ divider.setAttribute(DATA_RETICLE_LOG_ROW, '');
151
+ divider.setAttribute(DATA_KIND, HANDOVER_KIND);
152
+ divider.setAttribute(DATA_ACTOR, actor);
153
+ const label = document.createElement('span');
154
+ label.className = LOG_TEXT_CLASS;
155
+ label.textContent = HANDOVER_TEXT[actor];
156
+ divider.appendChild(label);
157
+ container.appendChild(divider);
158
+ }
159
+ if (driven)
160
+ container.setAttribute(LAST_ACTOR_ATTR, actor);
115
161
  const row = document.createElement('div');
116
162
  row.setAttribute(DATA_RETICLE_LOG_ROW, '');
117
163
  row.setAttribute(DATA_KIND, kind);
164
+ row.setAttribute(DATA_ACTOR, actor);
165
+ if (kind === LOG_KIND.ACT)
166
+ row.setAttribute(DATA_STATE, 'running');
118
167
  const tsEl = document.createElement('span');
119
168
  tsEl.setAttribute(LOG_TIME_ATTR, '');
120
169
  tsEl.textContent = ts;
@@ -153,8 +202,9 @@ export function appendLogRow(container, kind, text, ts, logMax) {
153
202
  });
154
203
  return {
155
204
  result: (r) => {
205
+ row.setAttribute(DATA_STATE, r);
156
206
  if (r === LOG_RESULT.PASS) {
157
- resEl.textContent = '';
207
+ resEl.textContent = RESULT_GLYPH.pass;
158
208
  resEl.className = `${LOG_RES_CLASS} ${RESULT_CLASS.pass}`;
159
209
  return;
160
210
  }
@@ -7,8 +7,12 @@ export declare const REPORT_LINKS: {
7
7
  };
8
8
  export declare const REPORT_TEXT: {
9
9
  readonly TITLE: "Impact";
10
+ readonly COVERAGE: "Reticle Coverage";
11
+ readonly COVERAGE_HELP: "How much of this app Reticle has reached, touched and proved, from the coverage ledger in .reticle";
10
12
  readonly PROJECT: "This project";
11
- readonly GLOBAL: "Everything on this machine";
13
+ readonly GLOBAL: "All projects";
14
+ readonly GLOBAL_TITLE: "Every project on this computer";
15
+ readonly SCOPE_LABEL: "Show impact for";
12
16
  readonly HERO_DEFECTS: "checks Reticle refused to pass";
13
17
  readonly VERDICTS: "Verdicts";
14
18
  readonly PASSED: "passed";
@@ -27,6 +31,8 @@ export declare const REPORT_TEXT: {
27
31
  readonly CHART: "Verdicts, last 30 days";
28
32
  readonly DEFECTS: "What broke";
29
33
  readonly DEFECTS_MORE: "Manage all of them on the dashboard — triage, assign, and push to GitHub";
34
+ readonly DEFECTS_SEE_ALL: "See all on the dashboard";
35
+ readonly DEFECTS_SEE_ALL_TITLE: "Sign up free, link this project, and see every bug Reticle caught";
30
36
  readonly DEFECT_LINK_TITLE: "Open on the dashboard to triage or push to GitHub";
31
37
  readonly LOCAL_ONLY: "This record stops at this machine.";
32
38
  readonly LOCAL_ONLY_ACTION: "reticle login";
@@ -48,3 +54,7 @@ export declare function buildXShareUrl(text: string): string;
48
54
  export declare function buildLinkedInShareUrl(): string;
49
55
  export declare function buildReferralText(): string;
50
56
  export declare function parseImpactSnapshot(value: unknown): ImpactSnapshot | undefined;
57
+ export declare const COVERAGE_LEVELS: readonly {
58
+ key: string;
59
+ label: string;
60
+ }[];
@@ -8,8 +8,12 @@ export const REPORT_LINKS = {
8
8
  const SHARE_VIA_HANDLE = '';
9
9
  export const REPORT_TEXT = {
10
10
  TITLE: 'Impact',
11
+ COVERAGE: 'Reticle Coverage',
12
+ COVERAGE_HELP: 'How much of this app Reticle has reached, touched and proved, from the coverage ledger in .reticle',
11
13
  PROJECT: 'This project',
12
- GLOBAL: 'Everything on this machine',
14
+ GLOBAL: 'All projects',
15
+ GLOBAL_TITLE: 'Every project on this computer',
16
+ SCOPE_LABEL: 'Show impact for',
13
17
  HERO_DEFECTS: 'checks Reticle refused to pass',
14
18
  VERDICTS: 'Verdicts',
15
19
  PASSED: 'passed',
@@ -28,6 +32,8 @@ export const REPORT_TEXT = {
28
32
  CHART: 'Verdicts, last 30 days',
29
33
  DEFECTS: 'What broke',
30
34
  DEFECTS_MORE: 'Manage all of them on the dashboard — triage, assign, and push to GitHub',
35
+ DEFECTS_SEE_ALL: 'See all on the dashboard',
36
+ DEFECTS_SEE_ALL_TITLE: 'Sign up free, link this project, and see every bug Reticle caught',
31
37
  DEFECT_LINK_TITLE: 'Open on the dashboard to triage or push to GitHub',
32
38
  LOCAL_ONLY: 'This record stops at this machine.',
33
39
  LOCAL_ONLY_ACTION: 'reticle login',
@@ -93,3 +99,10 @@ export function parseImpactSnapshot(value) {
93
99
  const parsed = ImpactSnapshotSchema.safeParse(value);
94
100
  return parsed.success ? parsed.data : undefined;
95
101
  }
102
+ export const COVERAGE_LEVELS = [
103
+ { key: 'reached', label: 'routes reached' },
104
+ { key: 'touched', label: 'controls touched' },
105
+ { key: 'proved', label: 'controls proved' },
106
+ { key: 'branched', label: 'write failures driven' },
107
+ { key: 'executed', label: 'code executed' },
108
+ ];
@@ -3,7 +3,9 @@ import { HudPanel, HudToggle, HudView } from '@reticlehq/core';
3
3
  import { isReticleUi } from '../dom/dom-ignore.js';
4
4
  import { nativeSetTimeout } from '../timers/native/native-timers.js';
5
5
  import { CHAT_ATTR, MIN_ATTR, REPORT_ATTR, SETTINGS_ATTR } from './presenter-config.js';
6
+ import { CAROUSEL_SLIDE_ATTR } from './carousel/carousel.js';
6
7
  const PREFIX = 'data-reticle-';
8
+ const PAGE_OPEN_ATTR = 'data-reticle-page-open';
7
9
  const TOGGLE_ROLES = new Set(['switch', 'checkbox']);
8
10
  export function controlIdOf(el) {
9
11
  for (const attr of Array.from(el.attributes)) {
@@ -36,6 +38,11 @@ function viewOf(root) {
36
38
  if ('1' === root.getAttribute(REPORT_ATTR)) {
37
39
  return { view: HudView.EXPANDED, panel: HudPanel.REPORT };
38
40
  }
41
+ const page = root.getAttribute(PAGE_OPEN_ATTR);
42
+ if ('flows' === page)
43
+ return { view: HudView.EXPANDED, panel: HudPanel.FLOWS };
44
+ if ('annotations' === page)
45
+ return { view: HudView.EXPANDED, panel: HudPanel.NOTES };
39
46
  if ('1' === root.getAttribute(CHAT_ATTR))
40
47
  return { view: HudView.EXPANDED, panel: HudPanel.CHAT };
41
48
  return { view: HudView.COLLAPSED, panel: HudPanel.NONE };
@@ -73,15 +80,37 @@ export function installHudTelemetry(doc, root, report) {
73
80
  last = key;
74
81
  send(now);
75
82
  };
83
+ let lastSlide = '';
84
+ const onSlide = () => {
85
+ if (HudPanel.CHAT !== viewOf(root).panel)
86
+ return;
87
+ const shown = root.querySelector(`[${CAROUSEL_SLIDE_ATTR}]:not([hidden])`);
88
+ const slide = shown?.getAttribute(CAROUSEL_SLIDE_ATTR) ?? '';
89
+ if (0 === slide.length || slide === lastSlide)
90
+ return;
91
+ lastSlide = slide;
92
+ send({ slide });
93
+ };
94
+ const slides = new MutationObserver(onSlide);
95
+ slides.observe(root, {
96
+ subtree: true,
97
+ attributes: true,
98
+ attributeFilter: ['data-active', 'hidden'],
99
+ });
76
100
  doc.addEventListener('click', onPress, true);
77
- const observer = new MutationObserver(onChange);
101
+ const observer = new MutationObserver((records) => {
102
+ onChange();
103
+ if (0 < records.length)
104
+ onSlide();
105
+ });
78
106
  observer.observe(root, {
79
107
  attributes: true,
80
- attributeFilter: [MIN_ATTR, CHAT_ATTR, SETTINGS_ATTR, REPORT_ATTR],
108
+ attributeFilter: [MIN_ATTR, CHAT_ATTR, SETTINGS_ATTR, REPORT_ATTR, PAGE_OPEN_ATTR],
81
109
  });
82
110
  onChange();
83
111
  return () => {
84
112
  doc.removeEventListener('click', onPress, true);
85
113
  observer.disconnect();
114
+ slides.disconnect();
86
115
  };
87
116
  }
@@ -14,6 +14,7 @@ declare const BODIES: {
14
14
  message: string;
15
15
  gear: string;
16
16
  layout: string;
17
+ notes: string;
17
18
  trash: string;
18
19
  help: string;
19
20
  'caret-right': string;
@@ -6,14 +6,15 @@ const BODIES = {
6
6
  'caret-down': '<path d="m19 9l-7 7l-7-7"/>',
7
7
  check: '<path d="m5 13l4 4L19 7"/>',
8
8
  remove: '<path d="m4.5 19.5l15-15m-15 0l15 15"/>',
9
- pause: '<path d="M10 9v6m4-6v6m7-3a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/>',
10
- play: '<g><path d="m14.752 11.168l-3.197-2.132A1 1 0 0 0 10 9.87v4.263a1 1 0 0 0 1.555.832l3.197-2.132a1 1 0 0 0 0-1.664"/><path d="M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/></g>',
11
- stop: '<g><path d="M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/><path d="M9 10a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1z"/></g>',
9
+ pause: '<path d="M8 5v14M16 5v14"/>',
10
+ play: '<path d="M8 5.75v12.5L18 12 8 5.75Z"/>',
11
+ stop: '<rect x="6.5" y="6.5" width="11" height="11" rx="2"/>',
12
12
  copy: '<path d="M8 7v8a2 2 0 0 0 2 2h6M8 7V5a2 2 0 0 1 2-2h4.586a1 1 0 0 1 .707.293l4.414 4.414a1 1 0 0 1 .293.707V15a2 2 0 0 1-2 2h-2M8 7H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-2"/>',
13
13
  download: '<path d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"/>',
14
14
  message: '<path d="M8.625 9.75a.375.375 0 1 1-.75 0a.375.375 0 0 1 .75 0Zm0 0H8.25m4.125 0a.375.375 0 1 1-.75 0a.375.375 0 0 1 .75 0Zm0 0H12m4.125 0a.375.375 0 1 1-.75 0a.375.375 0 0 1 .75 0Zm0 0h-.375m-13.5 3.01c0 1.6 1.123 2.994 2.707 3.227c1.087.16 2.185.283 3.293.369V21l4.184-4.183a1.14 1.14 0 0 1 .778-.332a48.294 48.294 0 0 0 5.83-.498c1.585-.233 2.708-1.626 2.708-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z"/>',
15
15
  gear: '<g><path d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87c.074.04.147.083.22.127c.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 0 1 0 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 0 1 0-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124c.072-.044.146-.087.22-.128c.332-.183.582-.495.644-.869l.214-1.281Z"/><path d="M15 12a3 3 0 1 1-6 0a3 3 0 0 1 6 0Z"/></g>',
16
16
  layout: '<path d="M3.75 6A2.25 2.25 0 0 1 6 3.75h2.25A2.25 2.25 0 0 1 10.5 6v2.25a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V6Zm0 9.75A2.25 2.25 0 0 1 6 13.5h2.25a2.25 2.25 0 0 1 2.25 2.25V18a2.25 2.25 0 0 1-2.25 2.25H6A2.25 2.25 0 0 1 3.75 18v-2.25ZM13.5 6a2.25 2.25 0 0 1 2.25-2.25H18A2.25 2.25 0 0 1 20.25 6v2.25A2.25 2.25 0 0 1 18 10.5h-2.25a2.25 2.25 0 0 1-2.25-2.25V6Zm0 9.75a2.25 2.25 0 0 1 2.25-2.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-2.25A2.25 2.25 0 0 1 13.5 18v-2.25Z"/>',
17
+ notes: '<path d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75a2.25 2.25 0 0 0-.1-.664m-5.8 0A2.251 2.251 0 0 1 13.5 2.25H15a2.25 2.25 0 0 1 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25ZM6.75 12h.008v.008H6.75V12Zm0 3h.008v.008H6.75V15Zm0 3h.008v.008H6.75V18Z"/>',
17
18
  trash: '<path d="m19 7l-.867 12.142A2 2 0 0 1 16.138 21H7.862a2 2 0 0 1-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v3M4 7h16"/>',
18
19
  help: '<path d="M8.228 9c.549-1.165 2.03-2 3.772-2c2.21 0 4 1.343 4 3c0 1.4-1.278 2.575-3.006 2.907c-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0"/>',
19
20
  'caret-right': '<path d="m9 5l7 7l-7 7"/>',
@@ -13,6 +13,7 @@ export declare const PresenterIcon: {
13
13
  readonly COPY: "copy";
14
14
  readonly DOWNLOAD: "download";
15
15
  readonly MESSAGE: "message";
16
+ readonly NOTES: "notes";
16
17
  readonly GEAR: "gear";
17
18
  readonly LAYOUT: "layout";
18
19
  readonly TRASH: "trash";
@@ -30,6 +31,7 @@ export declare const PRESENTER_ICON_SIZE: {
30
31
  readonly SEND: 14;
31
32
  readonly MIN: 12;
32
33
  readonly HELP: 12;
34
+ readonly NAV: 18;
33
35
  readonly TOOLBAR: 18;
34
36
  readonly FAB: 22;
35
37
  };
@@ -13,6 +13,7 @@ export const PresenterIcon = {
13
13
  COPY: 'copy',
14
14
  DOWNLOAD: 'download',
15
15
  MESSAGE: 'message',
16
+ NOTES: 'notes',
16
17
  GEAR: 'gear',
17
18
  LAYOUT: 'layout',
18
19
  TRASH: 'trash',
@@ -29,6 +30,7 @@ export const PRESENTER_ICON_SIZE = {
29
30
  SEND: 14,
30
31
  MIN: 12,
31
32
  HELP: 12,
33
+ NAV: 18,
32
34
  TOOLBAR: 18,
33
35
  FAB: 22,
34
36
  };
@@ -7,7 +7,7 @@ export declare const ACCOUNT_MENU_ATTR = "data-reticle-account-menu";
7
7
  export declare const ACCOUNT_SIGNOUT_ATTR = "data-reticle-account-signout";
8
8
  export declare const ACCOUNT_TEXT: {
9
9
  readonly SIGNED_OUT: "Sign in";
10
- readonly SIGNIN_TITLE: "Run `reticle login` in your terminal — click to copy the command";
10
+ readonly SIGNIN_TITLE: "Sign in through your browser. Also copies `reticle login`, for a terminal";
11
11
  readonly SIGNIN_COMMAND: "reticle login";
12
12
  readonly DASHBOARD_TITLE: "Open this project on the dashboard";
13
13
  readonly SYNC_TITLE: "Push to the dashboard now, instead of waiting for the next sync";
@@ -19,9 +19,10 @@ export declare const ACCOUNT_TEXT: {
19
19
  readonly DASHBOARD_ACTION: "Open dashboard";
20
20
  readonly LINK_HINT: "Not linked — run `reticle link` to keep a record on the dashboard";
21
21
  readonly LINK_COMMAND: "reticle link";
22
- readonly SIGNOUT_ACTION: "Sign out";
23
- readonly SIGNOUT_TITLE: "Run `reticle logout` in your terminal — click to copy the command";
22
+ readonly SIGNOUT_ACTION: "Copy sign-out command";
23
+ readonly SIGNOUT_TITLE: "Copy `reticle logout` to run in your terminal";
24
24
  readonly SIGNOUT_COMMAND: "reticle logout";
25
+ readonly SIGNOUT_COPY_FAILED: "Run reticle logout in terminal";
25
26
  readonly PROJECT_LABEL: "Project";
26
27
  readonly HOST_LABEL: "Host";
27
28
  readonly VERDICTS_LABEL: "Verdicts";
@@ -37,4 +38,4 @@ export declare function accountInitials(org: string | undefined): string;
37
38
  export declare function accountControlHtml(account: AccountState | undefined, details?: AccountDetails, offerSignIn?: boolean): string;
38
39
  export declare function accountCapsuleHtml(account: AccountState | undefined, dashboardUrl?: string, offerSignIn?: boolean): string;
39
40
  export declare function syncButtonHtml(dashboardUrl: string | undefined): string;
40
- export declare function mountAccountControl(root: HTMLElement): () => void;
41
+ export declare function mountAccountControl(root: HTMLElement, onSignIn?: () => void): () => void;
@@ -8,7 +8,7 @@ export const ACCOUNT_MENU_ATTR = 'data-reticle-account-menu';
8
8
  export const ACCOUNT_SIGNOUT_ATTR = 'data-reticle-account-signout';
9
9
  export const ACCOUNT_TEXT = {
10
10
  SIGNED_OUT: 'Sign in',
11
- SIGNIN_TITLE: 'Run `reticle login` in your terminal — click to copy the command',
11
+ SIGNIN_TITLE: 'Sign in through your browser. Also copies `reticle login`, for a terminal',
12
12
  SIGNIN_COMMAND: 'reticle login',
13
13
  DASHBOARD_TITLE: 'Open this project on the dashboard',
14
14
  SYNC_TITLE: 'Push to the dashboard now, instead of waiting for the next sync',
@@ -20,9 +20,10 @@ export const ACCOUNT_TEXT = {
20
20
  DASHBOARD_ACTION: 'Open dashboard',
21
21
  LINK_HINT: 'Not linked — run `reticle link` to keep a record on the dashboard',
22
22
  LINK_COMMAND: 'reticle link',
23
- SIGNOUT_ACTION: 'Sign out',
24
- SIGNOUT_TITLE: 'Run `reticle logout` in your terminal — click to copy the command',
23
+ SIGNOUT_ACTION: 'Copy sign-out command',
24
+ SIGNOUT_TITLE: 'Copy `reticle logout` to run in your terminal',
25
25
  SIGNOUT_COMMAND: 'reticle logout',
26
+ SIGNOUT_COPY_FAILED: 'Run reticle logout in terminal',
26
27
  PROJECT_LABEL: 'Project',
27
28
  HOST_LABEL: 'Host',
28
29
  VERDICTS_LABEL: 'Verdicts',
@@ -95,7 +96,7 @@ export function syncButtonHtml(dashboardUrl) {
95
96
  return '';
96
97
  return `<button type="button" class="reticle-sync-now" ${SYNC_BTN_ATTR} title="${ACCOUNT_TEXT.SYNC_TITLE}" aria-label="${ACCOUNT_TEXT.SYNC_TITLE}">${hiIconHtml(PresenterIcon.SYNC, PRESENTER_ICON_SIZE.HELP)}</button>`;
97
98
  }
98
- export function mountAccountControl(root) {
99
+ export function mountAccountControl(root, onSignIn) {
99
100
  const controller = new AbortController();
100
101
  const { signal } = controller;
101
102
  const closeAll = (except) => {
@@ -111,14 +112,27 @@ export function mountAccountControl(root) {
111
112
  trigger.setAttribute('aria-expanded', 'false');
112
113
  }
113
114
  };
114
- const flashCopied = (el) => {
115
+ const flashLabel = (el, value) => {
115
116
  const label = el.querySelector('span') ?? el;
116
117
  const previous = label.textContent;
117
- label.textContent = ACCOUNT_TEXT.COPIED;
118
+ label.textContent = value;
118
119
  setTimeout(() => {
119
120
  label.textContent = previous;
120
121
  }, ACCOUNT_COPIED_MS);
121
122
  };
123
+ const copyCommand = async (command, el) => {
124
+ try {
125
+ if (navigator.clipboard === undefined)
126
+ throw new Error('Clipboard unavailable');
127
+ await navigator.clipboard.writeText(command);
128
+ flashLabel(el, ACCOUNT_TEXT.COPIED);
129
+ }
130
+ catch {
131
+ flashLabel(el, command === ACCOUNT_TEXT.SIGNOUT_COMMAND
132
+ ? ACCOUNT_TEXT.SIGNOUT_COPY_FAILED
133
+ : `Run ${command} in terminal`);
134
+ }
135
+ };
122
136
  root.addEventListener('click', (event) => {
123
137
  const target = event.target;
124
138
  if (!(target instanceof Element))
@@ -145,16 +159,15 @@ export function mountAccountControl(root) {
145
159
  event.stopPropagation();
146
160
  const command = copier.getAttribute('data-reticle-copy') ?? '';
147
161
  if (command.length > 0)
148
- void navigator.clipboard?.writeText(command).catch(() => undefined);
149
- flashCopied(copier);
162
+ void copyCommand(command, copier);
150
163
  return;
151
164
  }
152
165
  const signin = target.closest(`[${ACCOUNT_SIGNIN_ATTR}]`);
153
166
  if (signin instanceof HTMLElement) {
154
167
  event.preventDefault();
155
168
  event.stopPropagation();
156
- void navigator.clipboard?.writeText(ACCOUNT_TEXT.SIGNIN_COMMAND).catch(() => undefined);
157
- flashCopied(signin);
169
+ onSignIn?.();
170
+ void copyCommand(ACCOUNT_TEXT.SIGNIN_COMMAND, signin);
158
171
  return;
159
172
  }
160
173
  closeAll();
@@ -0,0 +1,21 @@
1
+ import { type AccountState, type HarnessConfig } from '@reticlehq/core';
2
+ import type { AnnotationItem } from '../review/annotator.js';
3
+ export type ChatView = 'activity' | 'flows' | 'annotations';
4
+ export declare function platformBase(config: HarnessConfig | undefined, account: AccountState): string;
5
+ export declare const CHAT_VIEWS_HTML = "\n <div data-reticle-harness-spot class=\"reticle-harness-spot\" hidden></div>";
6
+ export declare const FLOWS_PAGE_HTML: string;
7
+ export declare const CHAT_VIEWS_NAV_HTML: string;
8
+ export declare const ANNOTATIONS_HTML: string;
9
+ export declare const CHAT_VIEWS_CSS: string;
10
+ export declare class ChatViews {
11
+ #private;
12
+ constructor(onHarness: (enabled: boolean) => void, onImpact: () => void, onOpenChat: (view: ChatView) => void);
13
+ mount(root: HTMLElement): void;
14
+ teardown(): void;
15
+ open(view: ChatView): void;
16
+ closePage(): void;
17
+ paintAccount(account: AccountState | undefined): void;
18
+ paintHarness(config: HarnessConfig | undefined): void;
19
+ paintImpact(verdicts: number): void;
20
+ paintAnnotations(items: readonly AnnotationItem[]): void;
21
+ }