@reticlehq/browser 2.0.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 (191) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +17 -0
  3. package/dist/actions/actions-dom.d.ts +29 -0
  4. package/dist/actions/actions-dom.d.ts.map +1 -0
  5. package/dist/actions/actions-dom.js +153 -0
  6. package/dist/actions/actions-dom.js.map +1 -0
  7. package/dist/actions/actions.d.ts +92 -0
  8. package/dist/actions/actions.d.ts.map +1 -0
  9. package/dist/actions/actions.js +348 -0
  10. package/dist/actions/actions.js.map +1 -0
  11. package/dist/actions/scroll.d.ts +19 -0
  12. package/dist/actions/scroll.d.ts.map +1 -0
  13. package/dist/actions/scroll.js +44 -0
  14. package/dist/actions/scroll.js.map +1 -0
  15. package/dist/commands/commands.d.ts +5 -0
  16. package/dist/commands/commands.d.ts.map +1 -0
  17. package/dist/commands/commands.js +246 -0
  18. package/dist/commands/commands.js.map +1 -0
  19. package/dist/dom/a11y.d.ts +20 -0
  20. package/dist/dom/a11y.d.ts.map +1 -0
  21. package/dist/dom/a11y.js +263 -0
  22. package/dist/dom/a11y.js.map +1 -0
  23. package/dist/dom/auto-anchor.d.ts +66 -0
  24. package/dist/dom/auto-anchor.d.ts.map +1 -0
  25. package/dist/dom/auto-anchor.js +75 -0
  26. package/dist/dom/auto-anchor.js.map +1 -0
  27. package/dist/dom/dom-ignore.d.ts +7 -0
  28. package/dist/dom/dom-ignore.d.ts.map +1 -0
  29. package/dist/dom/dom-ignore.js +21 -0
  30. package/dist/dom/dom-ignore.js.map +1 -0
  31. package/dist/dom/query.d.ts +6 -0
  32. package/dist/dom/query.d.ts.map +1 -0
  33. package/dist/dom/query.js +236 -0
  34. package/dist/dom/query.js.map +1 -0
  35. package/dist/dom/refs.d.ts +15 -0
  36. package/dist/dom/refs.d.ts.map +1 -0
  37. package/dist/dom/refs.js +36 -0
  38. package/dist/dom/refs.js.map +1 -0
  39. package/dist/dom/snapshot.d.ts +22 -0
  40. package/dist/dom/snapshot.d.ts.map +1 -0
  41. package/dist/dom/snapshot.js +171 -0
  42. package/dist/dom/snapshot.js.map +1 -0
  43. package/dist/dom/theme.d.ts +26 -0
  44. package/dist/dom/theme.d.ts.map +1 -0
  45. package/dist/dom/theme.js +90 -0
  46. package/dist/dom/theme.js.map +1 -0
  47. package/dist/index.d.ts +25 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +32 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/observers/animation.d.ts +4 -0
  52. package/dist/observers/animation.d.ts.map +1 -0
  53. package/dist/observers/animation.js +35 -0
  54. package/dist/observers/animation.js.map +1 -0
  55. package/dist/observers/console.d.ts +4 -0
  56. package/dist/observers/console.d.ts.map +1 -0
  57. package/dist/observers/console.js +58 -0
  58. package/dist/observers/console.js.map +1 -0
  59. package/dist/observers/dom.d.ts +4 -0
  60. package/dist/observers/dom.d.ts.map +1 -0
  61. package/dist/observers/dom.js +96 -0
  62. package/dist/observers/dom.js.map +1 -0
  63. package/dist/observers/health.d.ts +8 -0
  64. package/dist/observers/health.d.ts.map +1 -0
  65. package/dist/observers/health.js +33 -0
  66. package/dist/observers/health.js.map +1 -0
  67. package/dist/observers/network.d.ts +11 -0
  68. package/dist/observers/network.d.ts.map +1 -0
  69. package/dist/observers/network.js +128 -0
  70. package/dist/observers/network.js.map +1 -0
  71. package/dist/observers/route.d.ts +4 -0
  72. package/dist/observers/route.d.ts.map +1 -0
  73. package/dist/observers/route.js +56 -0
  74. package/dist/observers/route.js.map +1 -0
  75. package/dist/observers/scroll.d.ts +4 -0
  76. package/dist/observers/scroll.d.ts.map +1 -0
  77. package/dist/observers/scroll.js +42 -0
  78. package/dist/observers/scroll.js.map +1 -0
  79. package/dist/observers/types.d.ts +6 -0
  80. package/dist/observers/types.d.ts.map +1 -0
  81. package/dist/observers/types.js +2 -0
  82. package/dist/observers/types.js.map +1 -0
  83. package/dist/presenter/overlay.d.ts +12 -0
  84. package/dist/presenter/overlay.d.ts.map +1 -0
  85. package/dist/presenter/overlay.js +31 -0
  86. package/dist/presenter/overlay.js.map +1 -0
  87. package/dist/presenter/presenter-config.d.ts +86 -0
  88. package/dist/presenter/presenter-config.d.ts.map +1 -0
  89. package/dist/presenter/presenter-config.js +51 -0
  90. package/dist/presenter/presenter-config.js.map +1 -0
  91. package/dist/presenter/presenter-controls.d.ts +74 -0
  92. package/dist/presenter/presenter-controls.d.ts.map +1 -0
  93. package/dist/presenter/presenter-controls.js +360 -0
  94. package/dist/presenter/presenter-controls.js.map +1 -0
  95. package/dist/presenter/presenter-effects.d.ts +14 -0
  96. package/dist/presenter/presenter-effects.d.ts.map +1 -0
  97. package/dist/presenter/presenter-effects.js +40 -0
  98. package/dist/presenter/presenter-effects.js.map +1 -0
  99. package/dist/presenter/presenter-glow.d.ts +43 -0
  100. package/dist/presenter/presenter-glow.d.ts.map +1 -0
  101. package/dist/presenter/presenter-glow.js +126 -0
  102. package/dist/presenter/presenter-glow.js.map +1 -0
  103. package/dist/presenter/presenter-log.d.ts +43 -0
  104. package/dist/presenter/presenter-log.d.ts.map +1 -0
  105. package/dist/presenter/presenter-log.js +118 -0
  106. package/dist/presenter/presenter-log.js.map +1 -0
  107. package/dist/presenter/presenter-run-state.d.ts +48 -0
  108. package/dist/presenter/presenter-run-state.d.ts.map +1 -0
  109. package/dist/presenter/presenter-run-state.js +37 -0
  110. package/dist/presenter/presenter-run-state.js.map +1 -0
  111. package/dist/presenter/presenter-styles.d.ts +7 -0
  112. package/dist/presenter/presenter-styles.d.ts.map +1 -0
  113. package/dist/presenter/presenter-styles.js +118 -0
  114. package/dist/presenter/presenter-styles.js.map +1 -0
  115. package/dist/presenter/presenter-tally.d.ts +20 -0
  116. package/dist/presenter/presenter-tally.d.ts.map +1 -0
  117. package/dist/presenter/presenter-tally.js +38 -0
  118. package/dist/presenter/presenter-tally.js.map +1 -0
  119. package/dist/presenter/presenter-verbs.d.ts +2 -0
  120. package/dist/presenter/presenter-verbs.d.ts.map +1 -0
  121. package/dist/presenter/presenter-verbs.js +29 -0
  122. package/dist/presenter/presenter-verbs.js.map +1 -0
  123. package/dist/presenter/presenter.d.ts +89 -0
  124. package/dist/presenter/presenter.d.ts.map +1 -0
  125. package/dist/presenter/presenter.js +428 -0
  126. package/dist/presenter/presenter.js.map +1 -0
  127. package/dist/recorder/recorder-styles.d.ts +12 -0
  128. package/dist/recorder/recorder-styles.d.ts.map +1 -0
  129. package/dist/recorder/recorder-styles.js +45 -0
  130. package/dist/recorder/recorder-styles.js.map +1 -0
  131. package/dist/recorder/recorder.d.ts +60 -0
  132. package/dist/recorder/recorder.d.ts.map +1 -0
  133. package/dist/recorder/recorder.js +436 -0
  134. package/dist/recorder/recorder.js.map +1 -0
  135. package/dist/registry/adapters.d.ts +31 -0
  136. package/dist/registry/adapters.d.ts.map +1 -0
  137. package/dist/registry/adapters.js +47 -0
  138. package/dist/registry/adapters.js.map +1 -0
  139. package/dist/registry/capabilities.d.ts +25 -0
  140. package/dist/registry/capabilities.d.ts.map +1 -0
  141. package/dist/registry/capabilities.js +48 -0
  142. package/dist/registry/capabilities.js.map +1 -0
  143. package/dist/registry/commit-and-signal.d.ts +9 -0
  144. package/dist/registry/commit-and-signal.d.ts.map +1 -0
  145. package/dist/registry/commit-and-signal.js +12 -0
  146. package/dist/registry/commit-and-signal.js.map +1 -0
  147. package/dist/registry/domains.d.ts +15 -0
  148. package/dist/registry/domains.d.ts.map +1 -0
  149. package/dist/registry/domains.js +19 -0
  150. package/dist/registry/domains.js.map +1 -0
  151. package/dist/registry/emitter.d.ts +28 -0
  152. package/dist/registry/emitter.d.ts.map +1 -0
  153. package/dist/registry/emitter.js +27 -0
  154. package/dist/registry/emitter.js.map +1 -0
  155. package/dist/registry/stores.d.ts +9 -0
  156. package/dist/registry/stores.d.ts.map +1 -0
  157. package/dist/registry/stores.js +30 -0
  158. package/dist/registry/stores.js.map +1 -0
  159. package/dist/reticle-presenter-helpers.d.ts +19 -0
  160. package/dist/reticle-presenter-helpers.d.ts.map +1 -0
  161. package/dist/reticle-presenter-helpers.js +81 -0
  162. package/dist/reticle-presenter-helpers.js.map +1 -0
  163. package/dist/reticle.d.ts +113 -0
  164. package/dist/reticle.d.ts.map +1 -0
  165. package/dist/reticle.js +379 -0
  166. package/dist/reticle.js.map +1 -0
  167. package/dist/review/annotator.d.ts +36 -0
  168. package/dist/review/annotator.d.ts.map +1 -0
  169. package/dist/review/annotator.js +321 -0
  170. package/dist/review/annotator.js.map +1 -0
  171. package/dist/review/mark-anchor.d.ts +23 -0
  172. package/dist/review/mark-anchor.d.ts.map +1 -0
  173. package/dist/review/mark-anchor.js +74 -0
  174. package/dist/review/mark-anchor.js.map +1 -0
  175. package/dist/security/serialization.d.ts +6 -0
  176. package/dist/security/serialization.d.ts.map +1 -0
  177. package/dist/security/serialization.js +103 -0
  178. package/dist/security/serialization.js.map +1 -0
  179. package/dist/timers/clock.d.ts +6 -0
  180. package/dist/timers/clock.d.ts.map +1 -0
  181. package/dist/timers/clock.js +80 -0
  182. package/dist/timers/clock.js.map +1 -0
  183. package/dist/timers/native-timers.d.ts +37 -0
  184. package/dist/timers/native-timers.d.ts.map +1 -0
  185. package/dist/timers/native-timers.js +79 -0
  186. package/dist/timers/native-timers.js.map +1 -0
  187. package/dist/transport/transport.d.ts +54 -0
  188. package/dist/transport/transport.d.ts.map +1 -0
  189. package/dist/transport/transport.js +182 -0
  190. package/dist/transport/transport.js.map +1 -0
  191. package/package.json +52 -0
@@ -0,0 +1,321 @@
1
+ import { EventType } from '@reticlehq/core';
2
+ import { resolveMarkAnchor } from './mark-anchor.js';
3
+ import { nativeSetTimeout, nativeClearTimeout } from '../timers/native-timers.js';
4
+ /** The cursor must rest this long before the outline boxes the element under it — calm, not jumpy. */
5
+ const HIGHLIGHT_REST_MS = 130;
6
+ /** Single base attribute on every UI node (varied by VALUE) so `closest('[data-reticle-mark]')`
7
+ * catches the FAB, popover, and pins in one check, and the SDK's observers ignore them all. */
8
+ const MARK_ATTR = 'data-reticle-mark';
9
+ const ACTIVE_ATTR = 'data-reticle-mark-active';
10
+ const Z = 2147483640;
11
+ const sel = (role) => `[${MARK_ATTR}="${role}"]`;
12
+ const CSS = `
13
+ ${sel('fab')}{position:fixed;left:18px;bottom:18px;z-index:${String(Z + 2)};
14
+ font:500 13px/1 "Inter",system-ui,sans-serif;display:inline-flex;align-items:center;gap:7px;
15
+ padding:9px 13px;border-radius:11px;cursor:pointer;color:#e9ebf2;
16
+ background:linear-gradient(180deg,rgba(19,22,32,.92),rgba(13,15,22,.92));
17
+ border:1px solid rgba(255,255,255,.12);box-shadow:0 10px 30px -10px rgba(0,0,0,.6);
18
+ -webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);transition:transform .12s,border-color .15s;}
19
+ ${sel('fab')}:hover{transform:translateY(-1px);border-color:rgba(124,131,255,.55);}
20
+ ${sel('fab')}[data-on="1"]{color:#fff;border-color:#7c83ff;background:linear-gradient(180deg,#6366f1,#4f46e5);}
21
+ ${sel('dot')}{width:8px;height:8px;border-radius:50%;background:#ff7a7a;flex:none;}
22
+ ${sel('fab')}[data-on="1"] ${sel('dot')}{background:#fff;}
23
+ html[${ACTIVE_ATTR}] *{cursor:crosshair !important;}
24
+ /* The Flag button + its popover are interactive — keep the pointer cursor over them, not crosshair. */
25
+ html[${ACTIVE_ATTR}] ${sel('fab')},html[${ACTIVE_ATTR}] ${sel('fab')} *,html[${ACTIVE_ATTR}] ${sel('pop')},html[${ACTIVE_ATTR}] ${sel('pop')} *{cursor:pointer !important;}
26
+ /* The outline glides to the rested element with an ease (soothing), and fades rather than snapping. */
27
+ ${sel('hi')}{position:fixed;z-index:${String(Z + 1)};pointer-events:none;opacity:0;box-sizing:border-box;
28
+ border:2px solid #7c83ff;border-radius:6px;background:rgba(124,131,255,.12);box-shadow:0 0 0 2px rgba(124,131,255,.22);
29
+ transition:left .22s cubic-bezier(.22,1,.36,1),top .22s cubic-bezier(.22,1,.36,1),width .22s cubic-bezier(.22,1,.36,1),height .22s cubic-bezier(.22,1,.36,1),opacity .18s ease;}
30
+ ${sel('hi')}[data-on="1"]{opacity:1;}
31
+ ${sel('hilabel')}{position:absolute;top:-21px;left:-2px;background:#6366f1;color:#fff;
32
+ font:600 10.5px/1 "Inter",system-ui,sans-serif;padding:3px 6px;border-radius:5px;white-space:nowrap;
33
+ max-width:300px;overflow:hidden;text-overflow:ellipsis;}
34
+ ${sel('pin')}{position:fixed;z-index:${String(Z + 1)};width:22px;height:22px;margin:-11px 0 0 -11px;
35
+ border-radius:50% 50% 50% 2px;background:#ff5d5d;border:2px solid #fff;box-shadow:0 4px 12px -2px rgba(0,0,0,.5);
36
+ color:#fff;font:700 11px/18px "Inter",system-ui,sans-serif;text-align:center;pointer-events:none;}
37
+ ${sel('pop')}{position:fixed;z-index:${String(Z + 3)};width:280px;box-sizing:border-box;
38
+ background:linear-gradient(180deg,rgba(19,22,32,.96),rgba(13,15,22,.96));border:1px solid rgba(255,255,255,.14);
39
+ border-radius:14px;padding:12px;box-shadow:0 24px 60px -16px rgba(0,0,0,.7);
40
+ -webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px);font:13px/1.5 "Inter",system-ui,sans-serif;color:#e9ebf2;}
41
+ ${sel('pop')} .reticle-mark-where{color:#9aa0b2;font-size:11.5px;margin-bottom:7px;
42
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
43
+ ${sel('pop')} textarea{width:100%;box-sizing:border-box;min-height:62px;resize:vertical;
44
+ background:rgba(0,0,0,.3);border:1px solid rgba(255,255,255,.12);border-radius:9px;color:#e9ebf2;
45
+ font:13px/1.45 "Inter",system-ui,sans-serif;padding:8px;outline:none;}
46
+ ${sel('pop')} textarea:focus{border-color:#7c83ff;}
47
+ ${sel('pop')} .reticle-mark-row{display:flex;gap:8px;align-items:center;margin-top:9px;}
48
+ ${sel('pop')} .reticle-mark-hint{margin-right:auto;color:#6a7186;font-size:10.5px;letter-spacing:.02em;}
49
+ ${sel('pop')} button{font:600 12px/1 "Inter",system-ui,sans-serif;padding:8px 12px;border-radius:9px;cursor:pointer;border:1px solid rgba(255,255,255,.12);background:rgba(255,255,255,.05);color:#cdd2e2;}
50
+ ${sel('pop')} button[data-send]{background:#6366f1;border-color:#7c83ff;color:#fff;}
51
+ ${sel('pop')} button[data-send]:disabled{opacity:.5;cursor:default;}`;
52
+ export class Annotator {
53
+ #emit;
54
+ #now;
55
+ #onMark;
56
+ #root;
57
+ #fab;
58
+ #pop;
59
+ /** Hover outline box that shows WHICH element a click would flag (agentation-style). */
60
+ #hi;
61
+ #hiLabel;
62
+ /** Debounce timer — boxes the element only once the cursor rests, so a fast sweep doesn't flicker. */
63
+ #hiTimer;
64
+ #active = false;
65
+ #markCount = 0;
66
+ #onClick;
67
+ #onKeydown;
68
+ #onMove;
69
+ constructor(deps) {
70
+ this.#emit = deps.emit;
71
+ this.#now = deps.now;
72
+ this.#onMark = deps.onMark;
73
+ }
74
+ /** Whether annotate mode is currently capturing clicks. */
75
+ get active() {
76
+ return this.#active;
77
+ }
78
+ /** Number of marks sent this session (drives the pin numbering). */
79
+ get markCount() {
80
+ return this.#markCount;
81
+ }
82
+ mount() {
83
+ if (this.#root !== undefined || typeof document === 'undefined')
84
+ return;
85
+ const style = document.createElement('style');
86
+ style.setAttribute(MARK_ATTR, 'style');
87
+ style.textContent = CSS;
88
+ document.head.appendChild(style);
89
+ const root = document.createElement('div');
90
+ root.setAttribute(MARK_ATTR, 'root');
91
+ root.innerHTML = `<button type="button" ${MARK_ATTR}="fab" aria-label="Flag a bug for the agent">
92
+ <span ${MARK_ATTR}="dot"></span><span>Flag a bug</span></button>
93
+ <div ${MARK_ATTR}="hi"><span ${MARK_ATTR}="hilabel"></span></div>`;
94
+ document.body.appendChild(root);
95
+ this.#root = root;
96
+ this.#fab = root.querySelector(sel('fab')) ?? undefined;
97
+ this.#hi = root.querySelector(sel('hi')) ?? undefined;
98
+ this.#hiLabel = root.querySelector(sel('hilabel')) ?? undefined;
99
+ this.#fab?.addEventListener('click', (e) => {
100
+ e.stopPropagation();
101
+ this.toggle();
102
+ });
103
+ // Capture-phase click: intercept the FIRST click on a real page element while active.
104
+ this.#onClick = (ev) => this.#handleClick(ev);
105
+ document.addEventListener('click', this.#onClick, { capture: true });
106
+ // Hover outline: while active, box the element a click would flag — so you see what you're pointing at.
107
+ this.#onMove = (ev) => this.#scheduleMove(ev);
108
+ document.addEventListener('mousemove', this.#onMove, { passive: true, capture: true });
109
+ // Escape is the universal "back out": close an open popover, else leave annotate mode.
110
+ this.#onKeydown = (ev) => {
111
+ if (ev.key !== 'Escape' || !this.#active)
112
+ return;
113
+ if (this.#pop !== undefined)
114
+ this.#closePopover();
115
+ else
116
+ this.toggle(false);
117
+ };
118
+ document.addEventListener('keydown', this.#onKeydown);
119
+ }
120
+ destroy() {
121
+ if (this.#onClick !== undefined) {
122
+ document.removeEventListener('click', this.#onClick, { capture: true });
123
+ this.#onClick = undefined;
124
+ }
125
+ if (this.#onKeydown !== undefined) {
126
+ document.removeEventListener('keydown', this.#onKeydown);
127
+ this.#onKeydown = undefined;
128
+ }
129
+ if (this.#onMove !== undefined) {
130
+ document.removeEventListener('mousemove', this.#onMove, { capture: true });
131
+ this.#onMove = undefined;
132
+ }
133
+ if (this.#hiTimer !== undefined) {
134
+ nativeClearTimeout(this.#hiTimer);
135
+ this.#hiTimer = undefined;
136
+ }
137
+ this.#closePopover();
138
+ document.documentElement.removeAttribute(ACTIVE_ATTR);
139
+ this.#root?.remove();
140
+ document.querySelectorAll(`style[${MARK_ATTR}="style"]`).forEach((s) => s.remove());
141
+ this.#root = undefined;
142
+ this.#fab = undefined;
143
+ this.#active = false;
144
+ }
145
+ /** Turn annotate mode on/off. With no argument, flips the current state. */
146
+ toggle(on) {
147
+ this.#active = on ?? !this.#active;
148
+ this.#fab?.setAttribute('data-on', this.#active ? '1' : '0');
149
+ if (this.#active)
150
+ document.documentElement.setAttribute(ACTIVE_ATTR, '1');
151
+ else {
152
+ document.documentElement.removeAttribute(ACTIVE_ATTR);
153
+ this.#hideHighlight();
154
+ this.#closePopover();
155
+ }
156
+ }
157
+ #handleClick(ev) {
158
+ if (!this.#active)
159
+ return;
160
+ const target = ev.target;
161
+ if (!(target instanceof Element))
162
+ return;
163
+ if (target.closest(`[${MARK_ATTR}]`) !== null)
164
+ return; // never mark our own UI
165
+ ev.preventDefault();
166
+ ev.stopPropagation();
167
+ this.#openPopover(target, ev.clientX, ev.clientY);
168
+ }
169
+ /**
170
+ * Debounce the outline: while the cursor is moving the human is still travelling, so we wait for a
171
+ * brief rest before boxing the element under it (the box then eases into place via CSS). A pending
172
+ * timer is replaced on every move, so only the resting position ever paints.
173
+ */
174
+ #scheduleMove(ev) {
175
+ if (this.#hiTimer !== undefined)
176
+ nativeClearTimeout(this.#hiTimer);
177
+ this.#hiTimer = nativeSetTimeout(() => {
178
+ this.#hiTimer = undefined;
179
+ this.#handleMove(ev);
180
+ }, HIGHLIGHT_REST_MS);
181
+ }
182
+ /** Box the element under the cursor (when active, no popover open) so you see what a click flags. */
183
+ #handleMove(ev) {
184
+ if (this.#hi === undefined)
185
+ return;
186
+ const target = ev.target;
187
+ const skip = !this.#active ||
188
+ this.#pop !== undefined ||
189
+ !(target instanceof Element) ||
190
+ target.closest(`[${MARK_ATTR}]`) !== null;
191
+ if (skip) {
192
+ this.#hi.setAttribute('data-on', '0');
193
+ return;
194
+ }
195
+ const rect = target.getBoundingClientRect();
196
+ if (rect.width === 0 && rect.height === 0) {
197
+ this.#hi.setAttribute('data-on', '0');
198
+ return;
199
+ }
200
+ this.#hi.style.left = `${String(rect.left)}px`;
201
+ this.#hi.style.top = `${String(rect.top)}px`;
202
+ this.#hi.style.width = `${String(rect.width)}px`;
203
+ this.#hi.style.height = `${String(rect.height)}px`;
204
+ this.#hi.setAttribute('data-on', '1');
205
+ if (this.#hiLabel !== undefined)
206
+ this.#hiLabel.textContent = describeEl(target);
207
+ }
208
+ /** Hide the hover outline (annotate mode off, or a popover took over). Cancels any pending box. */
209
+ #hideHighlight() {
210
+ if (this.#hiTimer !== undefined) {
211
+ nativeClearTimeout(this.#hiTimer);
212
+ this.#hiTimer = undefined;
213
+ }
214
+ this.#hi?.setAttribute('data-on', '0');
215
+ }
216
+ #openPopover(el, x, y) {
217
+ this.#closePopover();
218
+ this.#hideHighlight(); // the popover is now the focus; drop the hover box
219
+ const resolved = resolveMarkAnchor(el);
220
+ const pop = document.createElement('div');
221
+ pop.setAttribute(MARK_ATTR, 'pop');
222
+ const where = resolved.source !== undefined
223
+ ? `${resolved.label} · ${resolved.source.file}:${String(resolved.source.line)}`
224
+ : resolved.label;
225
+ pop.innerHTML = `<div class="reticle-mark-where"></div>
226
+ <textarea placeholder="What's wrong here? The agent will read this and fix it."></textarea>
227
+ <div class="reticle-mark-row"><span class="reticle-mark-hint">⌘↵ send · esc cancel</span><button type="button" data-cancel>Cancel</button>
228
+ <button type="button" data-send disabled>Send to agent</button></div>`;
229
+ const whereEl = pop.querySelector('.reticle-mark-where');
230
+ if (whereEl !== null)
231
+ whereEl.textContent = where;
232
+ const left = Math.min(x, window.innerWidth - 296);
233
+ const top = Math.min(y + 12, window.innerHeight - 170);
234
+ pop.style.left = `${String(Math.max(8, left))}px`;
235
+ pop.style.top = `${String(Math.max(8, top))}px`;
236
+ document.body.appendChild(pop);
237
+ this.#pop = pop;
238
+ const textarea = pop.querySelector('textarea');
239
+ const send = pop.querySelector('button[data-send]');
240
+ const submit = () => {
241
+ const note = textarea?.value.trim() ?? '';
242
+ if (note.length === 0)
243
+ return; // never send an empty mark
244
+ this.#sendMark(note, resolved, x, y);
245
+ this.#closePopover();
246
+ };
247
+ textarea?.addEventListener('input', () => {
248
+ if (send !== null)
249
+ send.disabled = textarea.value.trim().length === 0;
250
+ });
251
+ // Keyboard ergonomics devs expect: ⌘/Ctrl+Enter sends, Esc cancels — without leaving the textarea.
252
+ textarea?.addEventListener('keydown', (e) => {
253
+ if (e.key === 'Escape') {
254
+ e.preventDefault();
255
+ this.#closePopover();
256
+ }
257
+ else if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
258
+ e.preventDefault();
259
+ submit();
260
+ }
261
+ });
262
+ textarea?.focus();
263
+ pop.querySelector('button[data-cancel]')?.addEventListener('click', () => this.#closePopover());
264
+ send?.addEventListener('click', submit);
265
+ }
266
+ #sendMark(note, resolved, x, y) {
267
+ const data = {
268
+ note,
269
+ anchor: resolved.anchor,
270
+ strategy: resolved.strategy,
271
+ label: resolved.label,
272
+ route: typeof location === 'undefined' ? '' : location.pathname + location.search,
273
+ };
274
+ if (resolved.source !== undefined)
275
+ data['source'] = resolved.source;
276
+ this.#emit(EventType.HUMAN_MARK, data);
277
+ this.#onMark?.(note, resolved.label); // echo into the live panel so the human sees the flag land
278
+ this.#markCount += 1;
279
+ this.#dropPin(x, y, this.#markCount);
280
+ }
281
+ #dropPin(x, y, n) {
282
+ if (this.#root === undefined)
283
+ return;
284
+ const pin = document.createElement('div');
285
+ pin.setAttribute(MARK_ATTR, 'pin');
286
+ pin.style.left = `${String(x)}px`;
287
+ pin.style.top = `${String(y)}px`;
288
+ pin.textContent = String(n);
289
+ this.#root.appendChild(pin);
290
+ // The pin fades after a moment so it confirms the mark landed without cluttering the page.
291
+ const ref = pin;
292
+ this.#now(); // touch the injected clock (kept for parity with the SDK's timing seams)
293
+ window.setTimeout(() => ref.remove(), 2600);
294
+ }
295
+ #closePopover() {
296
+ this.#pop?.remove();
297
+ this.#pop = undefined;
298
+ }
299
+ }
300
+ /**
301
+ * A short label for the hovered element — testid > aria-label > tag + text. Cheap on purpose (runs
302
+ * on every mousemove, so it does NOT call resolveMarkAnchor; the full anchor is resolved on click).
303
+ */
304
+ function describeEl(el) {
305
+ const testid = el.getAttribute('data-testid');
306
+ if (testid !== null && testid.length > 0)
307
+ return testid;
308
+ const tag = el.tagName.toLowerCase();
309
+ const aria = el.getAttribute('aria-label');
310
+ if (aria !== null && aria.length > 0)
311
+ return `${tag} "${aria}"`;
312
+ const text = (el.textContent ?? '').trim().replace(/\s+/g, ' ').slice(0, 40);
313
+ return text.length > 0 ? `${tag} "${text}"` : tag;
314
+ }
315
+ /** Construct + mount the annotator (mirrors installRecorder's ergonomics). */
316
+ export function installAnnotator(deps) {
317
+ const annotator = new Annotator(deps);
318
+ annotator.mount();
319
+ return annotator;
320
+ }
321
+ //# sourceMappingURL=annotator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotator.js","sourceRoot":"","sources":["../../src/review/annotator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { MarkAnchorStrategy } from '@reticlehq/core';
2
+ /**
3
+ * The element address carried by a human review mark: a re-resolvable anchor (auto-anchor's most
4
+ * durable tier for this element), its durability strategy, a human-legible label, and — crucially —
5
+ * the source file:line the agent should open. Source is reported INDEPENDENTLY of the anchor tier:
6
+ * a role-anchored element still carries its babel-stamped source so the agent can jump to the code.
7
+ */
8
+ export interface MarkAnchor {
9
+ anchor: string;
10
+ strategy: MarkAnchorStrategy;
11
+ label: string;
12
+ source?: {
13
+ file: string;
14
+ line: number;
15
+ };
16
+ }
17
+ /**
18
+ * Resolve a clicked element into the address a human review mark carries. Reuses the same
19
+ * auto-anchor machinery a recorded flow uses, so a mark pins to the element the way Reticle addresses
20
+ * it everywhere else — and always reports the source file:line when one is available.
21
+ */
22
+ export declare function resolveMarkAnchor(el: Element): MarkAnchor;
23
+ //# sourceMappingURL=mark-anchor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mark-anchor.d.ts","sourceRoot":"","sources":["../../src/review/mark-anchor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AASrD;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AAqCD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,OAAO,GAAG,UAAU,CAuBzD"}
@@ -0,0 +1,74 @@
1
+ import { MarkAnchorStrategy } from '@reticlehq/core';
2
+ import { AnchorStrategy, synthesizeAnchor } from '../dom/auto-anchor.js';
3
+ import { getAccessibleName, getRole } from '../dom/a11y.js';
4
+ import { identifyComponent } from '../registry/adapters.js';
5
+ /** Attribute names — defined locally per the recorder/query convention (no shared free string). */
6
+ const TESTID_ATTR = 'data-testid';
7
+ const SOURCE_ATTR = 'data-reticle-source';
8
+ /** AnchorStrategy and MarkAnchorStrategy share string values; map explicitly (no cross-cast). */
9
+ const STRATEGY = {
10
+ [AnchorStrategy.TESTID]: MarkAnchorStrategy.TESTID,
11
+ [AnchorStrategy.COMPONENT]: MarkAnchorStrategy.COMPONENT,
12
+ [AnchorStrategy.ROLE]: MarkAnchorStrategy.ROLE,
13
+ [AnchorStrategy.POSITION]: MarkAnchorStrategy.POSITION,
14
+ };
15
+ /** Parse a `data-reticle-source="file:line:column"` value into `{ file, line }` (column dropped). */
16
+ function parseSourceAttr(value) {
17
+ if (value === null)
18
+ return undefined;
19
+ const m = /^(.*):(\d+):(\d+)$/.exec(value);
20
+ if (m === null)
21
+ return undefined;
22
+ const file = m[1];
23
+ const line = Number(m[2]);
24
+ if (file === undefined || file.length === 0 || !Number.isFinite(line))
25
+ return undefined;
26
+ return { file, line };
27
+ }
28
+ /** Best source for the element: the framework adapter's, else the nearest babel-stamped attribute. */
29
+ function sourceFor(el, adapterSource) {
30
+ if (adapterSource !== undefined)
31
+ return { file: adapterSource.file, line: adapterSource.line };
32
+ const host = el.closest(`[${SOURCE_ATTR}]`);
33
+ return host !== null ? parseSourceAttr(host.getAttribute(SOURCE_ATTR)) : undefined;
34
+ }
35
+ /** A short, human-legible label for the element: `role "name"`, falling back to role / tag name. */
36
+ function labelFor(el, role, name) {
37
+ if (name.length > 0)
38
+ return role.length > 0 ? `${role} "${name}"` : `"${name}"`;
39
+ return role.length > 0 ? role : el.tagName.toLowerCase();
40
+ }
41
+ /**
42
+ * Resolve a clicked element into the address a human review mark carries. Reuses the same
43
+ * auto-anchor machinery a recorded flow uses, so a mark pins to the element the way Reticle addresses
44
+ * it everywhere else — and always reports the source file:line when one is available.
45
+ */
46
+ export function resolveMarkAnchor(el) {
47
+ const testid = el.getAttribute(TESTID_ATTR) ?? undefined;
48
+ const info = identifyComponent(el);
49
+ const component = info?.componentStack[0];
50
+ const source = sourceFor(el, info?.source);
51
+ const role = getRole(el);
52
+ const name = getAccessibleName(el);
53
+ const input = {};
54
+ if (testid !== undefined)
55
+ input.testid = testid;
56
+ if (component !== undefined)
57
+ input.component = component;
58
+ if (source !== undefined)
59
+ input.source = source;
60
+ if (role.length > 0)
61
+ input.role = role;
62
+ if (name.length > 0)
63
+ input.name = name;
64
+ const synthesized = synthesizeAnchor(input);
65
+ const out = {
66
+ anchor: synthesized.value,
67
+ strategy: STRATEGY[synthesized.strategy],
68
+ label: labelFor(el, role, name),
69
+ };
70
+ if (source !== undefined)
71
+ out.source = source;
72
+ return out;
73
+ }
74
+ //# sourceMappingURL=mark-anchor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mark-anchor.js","sourceRoot":"","sources":["../../src/review/mark-anchor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function isSensitiveKey(key: string): boolean;
2
+ /** Convert arbitrary app state into a bounded, redacted JSON-compatible value. */
3
+ export declare function sanitizeForTransport(value: unknown): unknown;
4
+ /** Serialize without allowing cycles, BigInt, getters, or secrets to break the transport. */
5
+ export declare function safeStringify(value: unknown): string;
6
+ //# sourceMappingURL=serialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/security/serialization.ts"],"names":[],"mappings":"AAgBA,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnD;AAmFD,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAW5D;AAED,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMpD"}
@@ -0,0 +1,103 @@
1
+ import { REDACTED_VALUE, TRANSPORT_LIMITS } from '@reticlehq/core';
2
+ const TRUNCATED_VALUE = '[TRUNCATED]';
3
+ const UNSERIALIZABLE_VALUE = '[UNSERIALIZABLE]';
4
+ const OMIT_VALUE = Symbol('omit');
5
+ const MAX_KEY_LENGTH = 256;
6
+ const MAX_TOTAL_CHARACTERS = Math.floor(TRANSPORT_LIMITS.MAX_MESSAGE_BYTES / 8);
7
+ const MAX_TOTAL_NODES = TRANSPORT_LIMITS.MAX_COLLECTION_ITEMS * 5;
8
+ // `token` must match auth CREDENTIALS, not compound design fields. Bare/separated `token(s)` and
9
+ // auth-prefixed tokens (accessToken, auth_token, sessionToken, …) are redacted; `colorToken`,
10
+ // `backgroundToken`, `tokenCount`, `designToken` are NOT — they were false-positives that redacted
11
+ // legitimate reticle_inspect/reticle_state output.
12
+ const SENSITIVE_KEY = /password|passwd|passcode|secret|(?:(?:access|refresh|auth|bearer|api|id|session|csrf|client)[-_]?tokens?|(?:^|[-_])tokens?(?=$|[-_]))|authorization|api[-_]?key|access[-_]?key|private[-_]?key|client[-_]?secret|credit[-_]?card|card[-_]?number|cvv|cvc|ssn/i;
13
+ export function isSensitiveKey(key) {
14
+ return SENSITIVE_KEY.test(key);
15
+ }
16
+ function boundedString(value, state, max) {
17
+ const allowed = Math.max(0, Math.min(max, state.remainingCharacters));
18
+ if (value.length <= allowed) {
19
+ state.remainingCharacters -= value.length;
20
+ return value;
21
+ }
22
+ const truncated = allowed <= TRUNCATED_VALUE.length
23
+ ? TRUNCATED_VALUE.slice(0, allowed)
24
+ : `${value.slice(0, allowed - TRUNCATED_VALUE.length)}${TRUNCATED_VALUE}`;
25
+ state.remainingCharacters -= truncated.length;
26
+ return truncated;
27
+ }
28
+ function sanitize(value, state, depth, key) {
29
+ if (key !== undefined && isSensitiveKey(key))
30
+ return REDACTED_VALUE;
31
+ if (depth > TRANSPORT_LIMITS.MAX_SERIALIZE_DEPTH || state.nodes >= MAX_TOTAL_NODES) {
32
+ return TRUNCATED_VALUE;
33
+ }
34
+ state.nodes += 1;
35
+ if (value === null || typeof value === 'boolean')
36
+ return value;
37
+ if (typeof value === 'string') {
38
+ return boundedString(value, state, key?.toLowerCase() === 'error'
39
+ ? TRANSPORT_LIMITS.MAX_ERROR_LENGTH
40
+ : TRANSPORT_LIMITS.MAX_STRING_LENGTH);
41
+ }
42
+ if (typeof value === 'number')
43
+ return Number.isFinite(value) ? value : null;
44
+ if (typeof value === 'bigint')
45
+ return value.toString();
46
+ if (typeof value === 'undefined' || typeof value === 'function' || typeof value === 'symbol') {
47
+ return OMIT_VALUE;
48
+ }
49
+ if (value instanceof Date)
50
+ return value.toISOString();
51
+ if (value instanceof Error) {
52
+ return {
53
+ name: boundedString(value.name, state, 256),
54
+ message: boundedString(value.message, state, TRANSPORT_LIMITS.MAX_ERROR_LENGTH),
55
+ };
56
+ }
57
+ if (state.seen.has(value))
58
+ return '[CIRCULAR]';
59
+ state.seen.add(value);
60
+ try {
61
+ if (Array.isArray(value)) {
62
+ return value.slice(0, TRANSPORT_LIMITS.MAX_COLLECTION_ITEMS).map((item) => {
63
+ const sanitized = sanitize(item, state, depth + 1);
64
+ return sanitized === OMIT_VALUE ? null : sanitized;
65
+ });
66
+ }
67
+ const out = Object.create(null);
68
+ for (const rawKey of Object.keys(value).slice(0, TRANSPORT_LIMITS.MAX_OBJECT_KEYS)) {
69
+ const safeKey = boundedString(rawKey, state, MAX_KEY_LENGTH);
70
+ try {
71
+ const sanitized = sanitize(value[rawKey], state, depth + 1, rawKey);
72
+ if (sanitized !== OMIT_VALUE)
73
+ out[safeKey] = sanitized;
74
+ }
75
+ catch {
76
+ out[safeKey] = UNSERIALIZABLE_VALUE;
77
+ }
78
+ }
79
+ return out;
80
+ }
81
+ finally {
82
+ state.seen.delete(value);
83
+ }
84
+ }
85
+ /** Convert arbitrary app state into a bounded, redacted JSON-compatible value. */
86
+ export function sanitizeForTransport(value) {
87
+ const sanitized = sanitize(value, {
88
+ seen: new WeakSet(),
89
+ remainingCharacters: MAX_TOTAL_CHARACTERS,
90
+ nodes: 0,
91
+ }, 0);
92
+ return sanitized === OMIT_VALUE ? null : sanitized;
93
+ }
94
+ /** Serialize without allowing cycles, BigInt, getters, or secrets to break the transport. */
95
+ export function safeStringify(value) {
96
+ try {
97
+ return JSON.stringify(sanitizeForTransport(value));
98
+ }
99
+ catch {
100
+ return JSON.stringify(UNSERIALIZABLE_VALUE);
101
+ }
102
+ }
103
+ //# sourceMappingURL=serialization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../src/security/serialization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function isClockFrozen(): boolean;
2
+ export declare function freezeClock(): void;
3
+ /** Run all timers due within the next `ms` of virtual time, in order. */
4
+ export declare function advanceClock(ms: number): void;
5
+ export declare function resetClock(): void;
6
+ //# sourceMappingURL=clock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../src/timers/clock.ts"],"names":[],"mappings":"AA2BA,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED,wBAAgB,WAAW,IAAI,IAAI,CAgClC;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAkB7C;AAED,wBAAgB,UAAU,IAAI,IAAI,CAWjC"}