@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,43 @@
1
+ import { PresenterMode } from '@reticlehq/core';
2
+ /** Activity-log entry kinds (presenter-only UI; never a wire string). */
3
+ export declare const LOG_KIND: {
4
+ readonly READ: "read";
5
+ readonly ACT: "act";
6
+ readonly NARRATION: "narration";
7
+ readonly HUMAN: "human";
8
+ };
9
+ export type LogKind = (typeof LOG_KIND)[keyof typeof LOG_KIND];
10
+ /** Prefix for a human-authored activity row ("🧑 you: <text>"). Presenter-only UI. */
11
+ export declare const HUMAN_ROW_PREFIX = "\uD83E\uDDD1 you: ";
12
+ /** Act-row outcome glyph keys (presenter-only UI). */
13
+ export declare const LOG_RESULT: {
14
+ readonly PASS: "pass";
15
+ readonly FAIL: "fail";
16
+ };
17
+ export type LogResult = (typeof LOG_RESULT)[keyof typeof LOG_RESULT];
18
+ /** HUD chip copy keyed by presenter mode (UI text, browser-local — not a wire string). */
19
+ export declare const CHIP_LABEL: Record<PresenterMode, string>;
20
+ export declare const DATA_RETICLE_LOG = "data-reticle-log";
21
+ /** CSS for the log feed (injected with the rest of the presenter stylesheet; vars inherit from the card). */
22
+ export declare const LOG_CSS = "\n[data-reticle-log]{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;\n gap:7px;padding:12px 14px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent;}\n[data-reticle-log]::-webkit-scrollbar{width:9px;}\n[data-reticle-log]::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:9px;border:2px solid transparent;background-clip:content-box;}\n[data-reticle-log]::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.26);background-clip:content-box;}\n[data-reticle-log-row]{display:flex;align-items:baseline;gap:8px;font-size:12px;line-height:1.45;\n animation:reticle-row-in .26s cubic-bezier(.16,1,.3,1);}\n@keyframes reticle-row-in{from{opacity:0;transform:translateY(5px);}to{opacity:1;transform:none;}}\n[data-reticle-log-ts]{flex:none;color:var(--reticle-faint);font-size:10px;font-variant-numeric:tabular-nums;padding-top:1px;}\n[data-reticle-log] .reticle-log-text{flex:1;min-width:0;color:#d6dae4;overflow-wrap:anywhere;word-break:break-word;}\n[data-reticle-log] .reticle-res{flex:none;font-weight:700;}\n[data-reticle-log-row][data-kind=\"human\"]{align-self:flex-end;max-width:88%;\n background:var(--reticle-accent-soft);border:1px solid var(--reticle-accent);border-radius:13px 13px 4px 13px;padding:6px 11px;}\n[data-reticle-log-row][data-kind=\"human\"] [data-reticle-log-ts]{display:none;}\n[data-reticle-log-row][data-kind=\"human\"] .reticle-log-text{color:var(--reticle-fg);}\n";
23
+ /** Handle returned from logRow/Presenter.log so the caller can stamp the outcome glyph later. */
24
+ export interface LogHandle {
25
+ result(r: LogResult): void;
26
+ }
27
+ /** Clamp a logMax option to a sane positive integer, falling back to the default. */
28
+ export declare function clampLogMax(n: number | undefined): number;
29
+ /**
30
+ * Pure, human-readable duration ("3s", "47s", "2m", "1h 4m") — no clock read, so it stays
31
+ * deterministic in tests. Used for both the per-row timestamp (time since session start) and the
32
+ * live "idle · {duration} since last action" heartbeat. Sub-second reads as "0s".
33
+ */
34
+ export declare function humanDuration(ms: number): string;
35
+ /** Per-row timestamp: time since the session's first row, human-readable (e.g. "2m", not "+132.4s"). */
36
+ export declare function formatElapsed(ms: number): string;
37
+ /**
38
+ * Build a log row from text (already trimmed) + a +elapsed timestamp, append it to the container,
39
+ * prune to logMax, auto-scroll to newest, and return a handle to stamp the outcome glyph later.
40
+ * Uses createElement/textContent (never innerHTML) so arbitrary narration text can't inject markup.
41
+ */
42
+ export declare function appendLogRow(container: HTMLElement, kind: LogKind, text: string, ts: string, logMax: number): LogHandle;
43
+ //# sourceMappingURL=presenter-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-log.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAShD,yEAAyE;AACzE,eAAO,MAAM,QAAQ;;;;;CAKX,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAE/D,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,uBAAa,CAAC;AAC3C,sDAAsD;AACtD,eAAO,MAAM,UAAU;;;CAA0C,CAAC;AAClE,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAGrE,0FAA0F;AAC1F,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAIpD,CAAC;AAWF,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAQnD,6GAA6G;AAC7G,eAAO,MAAM,OAAO,y9CAgBnB,CAAC;AAEF,iGAAiG;AACjG,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CAC5B;AAED,qFAAqF;AACrF,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED,wGAAwG;AACxG,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,WAAW,EACtB,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,GACb,SAAS,CAgCX"}
@@ -0,0 +1,118 @@
1
+ import { PresenterMode } from '@reticlehq/core';
2
+ // Activity-log UI for the presenter HUD: a persistent, timestamped, scrollable transcript of
3
+ // every read/act/narration. All strings here are presenter-only UI (chips, glyphs, attrs) — they
4
+ // never cross the browser↔bridge↔agent wire, so they stay as named consts (not protocol consts).
5
+ // All nodes carry data-reticle-* attrs so they're excluded from snapshots (see dom-ignore.ts).
6
+ /** Default cap on accumulated activity-log rows (bounds DOM). Presenter-local UI tunable. */
7
+ const DEFAULT_LOG_MAX = 50;
8
+ /** Activity-log entry kinds (presenter-only UI; never a wire string). */
9
+ export const LOG_KIND = {
10
+ READ: 'read',
11
+ ACT: 'act',
12
+ NARRATION: 'narration',
13
+ HUMAN: 'human',
14
+ };
15
+ /** Prefix for a human-authored activity row ("🧑 you: <text>"). Presenter-only UI. */
16
+ export const HUMAN_ROW_PREFIX = '🧑 you: ';
17
+ /** Act-row outcome glyph keys (presenter-only UI). */
18
+ export const LOG_RESULT = { PASS: 'pass', FAIL: 'fail' };
19
+ const LOG_CHIP = { read: 'READ', act: 'ACT', narration: '', human: '' };
20
+ /** HUD chip copy keyed by presenter mode (UI text, browser-local — not a wire string). */
21
+ export const CHIP_LABEL = {
22
+ [PresenterMode.IDLE]: '',
23
+ [PresenterMode.READING]: 'READING',
24
+ [PresenterMode.ACTING]: 'ACTING',
25
+ };
26
+ /** Map a log kind to the data-mode that styles its chip (narration/human show no chip). */
27
+ const LOG_CHIP_MODE = {
28
+ read: PresenterMode.READING,
29
+ act: PresenterMode.ACTING,
30
+ narration: PresenterMode.IDLE,
31
+ human: PresenterMode.IDLE,
32
+ };
33
+ const RESULT_GLYPH = { pass: '✓', fail: '✗' };
34
+ const RESULT_CLASS = { pass: 'reticle-pass', fail: 'reticle-fail' };
35
+ export const DATA_RETICLE_LOG = 'data-reticle-log';
36
+ const DATA_RETICLE_LOG_ROW = 'data-reticle-log-row';
37
+ const DATA_RETICLE_LOG_TS = 'data-reticle-log-ts';
38
+ const DATA_KIND = 'data-kind';
39
+ const LOG_TEXT_CLASS = 'reticle-log-text';
40
+ const LOG_RES_CLASS = 'reticle-res';
41
+ const LOG_CHIP_CLASS = 'reticle-chip';
42
+ /** CSS for the log feed (injected with the rest of the presenter stylesheet; vars inherit from the card). */
43
+ export const LOG_CSS = `
44
+ [data-reticle-log]{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;
45
+ gap:7px;padding:12px 14px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent;}
46
+ [data-reticle-log]::-webkit-scrollbar{width:9px;}
47
+ [data-reticle-log]::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:9px;border:2px solid transparent;background-clip:content-box;}
48
+ [data-reticle-log]::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.26);background-clip:content-box;}
49
+ [data-reticle-log-row]{display:flex;align-items:baseline;gap:8px;font-size:12px;line-height:1.45;
50
+ animation:reticle-row-in .26s cubic-bezier(.16,1,.3,1);}
51
+ @keyframes reticle-row-in{from{opacity:0;transform:translateY(5px);}to{opacity:1;transform:none;}}
52
+ [data-reticle-log-ts]{flex:none;color:var(--reticle-faint);font-size:10px;font-variant-numeric:tabular-nums;padding-top:1px;}
53
+ [data-reticle-log] .reticle-log-text{flex:1;min-width:0;color:#d6dae4;overflow-wrap:anywhere;word-break:break-word;}
54
+ [data-reticle-log] .reticle-res{flex:none;font-weight:700;}
55
+ [data-reticle-log-row][data-kind="human"]{align-self:flex-end;max-width:88%;
56
+ background:var(--reticle-accent-soft);border:1px solid var(--reticle-accent);border-radius:13px 13px 4px 13px;padding:6px 11px;}
57
+ [data-reticle-log-row][data-kind="human"] [data-reticle-log-ts]{display:none;}
58
+ [data-reticle-log-row][data-kind="human"] .reticle-log-text{color:var(--reticle-fg);}
59
+ `;
60
+ /** Clamp a logMax option to a sane positive integer, falling back to the default. */
61
+ export function clampLogMax(n) {
62
+ if (n === undefined || !Number.isFinite(n) || n <= 0)
63
+ return DEFAULT_LOG_MAX;
64
+ return Math.floor(n);
65
+ }
66
+ /**
67
+ * Pure, human-readable duration ("3s", "47s", "2m", "1h 4m") — no clock read, so it stays
68
+ * deterministic in tests. Used for both the per-row timestamp (time since session start) and the
69
+ * live "idle · {duration} since last action" heartbeat. Sub-second reads as "0s".
70
+ */
71
+ export function humanDuration(ms) {
72
+ const s = Math.max(0, Math.floor(ms / 1000));
73
+ if (s < 60)
74
+ return `${s}s`;
75
+ const m = Math.floor(s / 60);
76
+ if (m < 60)
77
+ return s % 60 === 0 ? `${m}m` : `${m}m ${s % 60}s`;
78
+ const h = Math.floor(m / 60);
79
+ return m % 60 === 0 ? `${h}h` : `${h}h ${m % 60}m`;
80
+ }
81
+ /** Per-row timestamp: time since the session's first row, human-readable (e.g. "2m", not "+132.4s"). */
82
+ export function formatElapsed(ms) {
83
+ return humanDuration(ms);
84
+ }
85
+ /**
86
+ * Build a log row from text (already trimmed) + a +elapsed timestamp, append it to the container,
87
+ * prune to logMax, auto-scroll to newest, and return a handle to stamp the outcome glyph later.
88
+ * Uses createElement/textContent (never innerHTML) so arbitrary narration text can't inject markup.
89
+ */
90
+ export function appendLogRow(container, kind, text, ts, logMax) {
91
+ const row = document.createElement('div');
92
+ row.setAttribute(DATA_RETICLE_LOG_ROW, '');
93
+ row.setAttribute(DATA_KIND, kind); // styles the human row as an accent chat bubble
94
+ const tsEl = document.createElement('span');
95
+ tsEl.setAttribute(DATA_RETICLE_LOG_TS, '');
96
+ tsEl.textContent = ts;
97
+ const chip = document.createElement('span');
98
+ chip.className = LOG_CHIP_CLASS;
99
+ chip.setAttribute('data-mode', LOG_CHIP_MODE[kind]);
100
+ chip.textContent = LOG_CHIP[kind];
101
+ const textEl = document.createElement('span');
102
+ textEl.className = LOG_TEXT_CLASS;
103
+ textEl.textContent = text;
104
+ const resEl = document.createElement('span');
105
+ resEl.className = LOG_RES_CLASS;
106
+ row.append(tsEl, chip, textEl, resEl);
107
+ container.appendChild(row);
108
+ while (container.childElementCount > logMax)
109
+ container.firstElementChild?.remove();
110
+ container.scrollTop = container.scrollHeight;
111
+ return {
112
+ result: (r) => {
113
+ resEl.textContent = ` ${RESULT_GLYPH[r]}`;
114
+ resEl.className = `${LOG_RES_CLASS} ${RESULT_CLASS[r]}`;
115
+ },
116
+ };
117
+ }
118
+ //# sourceMappingURL=presenter-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-log.js","sourceRoot":"","sources":["../../src/presenter/presenter-log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { SessionState } from '@reticlehq/core';
2
+ import { type LogKind, type LogResult } from './presenter-log.js';
3
+ import { type Capabilities } from '../registry/capabilities.js';
4
+ /** The in-page run-state export (Copy/Export buttons). The full event ring-buffer is server-side. */
5
+ export interface PresenterRunState {
6
+ session: string;
7
+ url: string;
8
+ state: SessionState;
9
+ startedMs: number;
10
+ durationMs: number;
11
+ counts: {
12
+ reads: number;
13
+ acts: number;
14
+ narrations: number;
15
+ human: number;
16
+ passes: number;
17
+ fails: number;
18
+ };
19
+ capabilities: Capabilities;
20
+ log: {
21
+ at: number;
22
+ kind: LogKind;
23
+ text: string;
24
+ result?: LogResult;
25
+ }[];
26
+ }
27
+ /** Everything the controller hands the builder — the live fields a run state is computed from. */
28
+ interface RunStateInput {
29
+ sessionId: string;
30
+ state: SessionState;
31
+ startMs: number | undefined;
32
+ endMs: number | undefined;
33
+ now: number;
34
+ runLog: {
35
+ at: number;
36
+ kind: LogKind;
37
+ text: string;
38
+ result?: LogResult;
39
+ }[];
40
+ }
41
+ /**
42
+ * Compute the exported run-state from the controller's live fields: per-kind + pass/fail counts over
43
+ * the activity log, the session duration, and the current capability surface. Extracted from
44
+ * presenter.ts so the controller stays under the size cap; the counting is the same as before.
45
+ */
46
+ export declare function buildRunState(input: RunStateInput): PresenterRunState;
47
+ export {};
48
+ //# sourceMappingURL=presenter-run-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-run-state.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-run-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAwB,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEjF,qGAAqG;AACrG,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,YAAY,EAAE,YAAY,CAAC;IAC3B,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAA;KAAE,EAAE,CAAC;CACxE;AAED,kGAAkG;AAClG,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,CAAA;KAAE,EAAE,CAAC;CAC3E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,iBAAiB,CAqBrE"}
@@ -0,0 +1,37 @@
1
+ import { SessionState } from '@reticlehq/core';
2
+ import { LOG_KIND, LOG_RESULT } from './presenter-log.js';
3
+ import { getCapabilities } from '../registry/capabilities.js';
4
+ /**
5
+ * Compute the exported run-state from the controller's live fields: per-kind + pass/fail counts over
6
+ * the activity log, the session duration, and the current capability surface. Extracted from
7
+ * presenter.ts so the controller stays under the size cap; the counting is the same as before.
8
+ */
9
+ export function buildRunState(input) {
10
+ const start = input.startMs ?? input.now;
11
+ const counts = { reads: 0, acts: 0, narrations: 0, human: 0, passes: 0, fails: 0 };
12
+ for (const e of input.runLog) {
13
+ if (e.kind === LOG_KIND.READ)
14
+ counts.reads += 1;
15
+ else if (e.kind === LOG_KIND.ACT)
16
+ counts.acts += 1;
17
+ else if (e.kind === LOG_KIND.NARRATION)
18
+ counts.narrations += 1;
19
+ else if (e.kind === LOG_KIND.HUMAN)
20
+ counts.human += 1;
21
+ if (e.result === LOG_RESULT.PASS)
22
+ counts.passes += 1;
23
+ else if (e.result === LOG_RESULT.FAIL)
24
+ counts.fails += 1;
25
+ }
26
+ return {
27
+ session: input.sessionId,
28
+ url: typeof location === 'undefined' ? '' : location.href,
29
+ state: input.state,
30
+ startedMs: start,
31
+ durationMs: Math.max(0, (input.endMs ?? input.now) - start),
32
+ counts,
33
+ capabilities: getCapabilities(),
34
+ log: input.runLog.map((e) => ({ ...e })),
35
+ };
36
+ }
37
+ //# sourceMappingURL=presenter-run-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-run-state.js","sourceRoot":"","sources":["../../src/presenter/presenter-run-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAgC,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,eAAe,EAAqB,MAAM,6BAA6B,CAAC;AA+BjF;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAoB;IAChD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC;IACzC,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACnF,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;YAAE,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;aAC3C,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,GAAG;YAAE,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;aAC9C,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,SAAS;YAAE,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC;aAC1D,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,KAAK;YAAE,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,IAAI;YAAE,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;aAChD,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,IAAI;YAAE,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,SAAS;QACxB,GAAG,EAAE,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI;QACzD,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,SAAS,EAAE,KAAK;QAChB,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC3D,MAAM;QACN,YAAY,EAAE,eAAe,EAAE;QAC/B,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;KACzC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * All presenter overlay CSS — the glow border, synthetic cursor/ring/ripple, and the glassy HUD.
3
+ * Split out of presenter.ts so that file stays a cohesive controller under the size cap; this is
4
+ * pure style data (no behavior). LOG_CSS + CONTROLS_CSS are composed in at the end as before.
5
+ */
6
+ export declare const PRESENTER_CSS = "\n@import url(\"https://fonts.googleapis.com/css2?family=IBM+Plex+Serif:wght@400;500&family=Inter:wght@400;450;500;600&display=swap\");\n[data-reticle-glow]{position:fixed;inset:0;pointer-events:none;z-index:2147483600;opacity:0;\n transition:opacity .25s ease;box-shadow:inset 0 0 0 3px rgba(99,102,241,.9),inset 0 0 28px 6px rgba(99,102,241,.45);}\n[data-reticle-glow][data-on=\"1\"]{opacity:1;animation:reticle-pulse 1.6s ease-in-out infinite;}\n[data-reticle-glow][data-on=\"1\"][data-busy=\"1\"]{animation:reticle-shimmer 1.1s ease-in-out infinite;}\n@keyframes reticle-pulse{0%,100%{box-shadow:inset 0 0 0 3px rgba(99,102,241,.9),inset 0 0 22px 4px rgba(99,102,241,.35)}\n 50%{box-shadow:inset 0 0 0 3px rgba(124,127,242,1),inset 0 0 40px 10px rgba(99,102,241,.6)}}\n@keyframes reticle-shimmer{0%,100%{box-shadow:inset 0 0 0 3px rgba(124,127,242,1),inset 0 0 34px 8px rgba(99,102,241,.55)}\n 50%{box-shadow:inset 0 0 0 3px rgba(140,142,255,1),inset 0 0 48px 12px rgba(99,102,241,.7)}}\n[data-reticle-cursor]{position:fixed;top:0;left:0;width:22px;height:22px;margin:-11px 0 0 -11px;\n border:2px solid #6366f1;border-radius:50%;background:rgba(99,102,241,.25);pointer-events:none;\n z-index:2147483646;opacity:0;transition:transform .32s cubic-bezier(.22,1,.36,1),opacity .2s ease;}\n[data-reticle-cursor][data-on=\"1\"]{opacity:1;}\n[data-reticle-cursor]::after{content:\"\";position:absolute;inset:7px;border-radius:50%;background:#6366f1;}\n[data-reticle-ripple]{position:fixed;width:14px;height:14px;margin:-7px 0 0 -7px;border-radius:50%;\n background:rgba(99,102,241,.5);pointer-events:none;z-index:2147483645;animation:reticle-ripple .5s ease-out forwards;}\n@keyframes reticle-ripple{from{transform:scale(.4);opacity:.8}to{transform:scale(5);opacity:0}}\n[data-reticle-ring]{position:fixed;pointer-events:none;z-index:2147483644;border:2px solid #22c55e;border-radius:8px;\n box-shadow:0 0 0 3px rgba(34,197,94,.25);opacity:0;transition:opacity .15s ease;}\n[data-reticle-ring][data-on=\"1\"]{opacity:1;}\n[data-reticle-hud]{\n --reticle-accent:#7c83ff;--reticle-accent-soft:rgba(124,131,255,.16);\n --reticle-bg:rgba(13,15,22,.80);--reticle-bg2:rgba(19,22,32,.74);\n --reticle-fg:#e9ebf2;--reticle-muted:#9aa0b2;--reticle-faint:#6a7186;\n --reticle-line:rgba(255,255,255,.09);--reticle-line2:rgba(255,255,255,.05);\n --reticle-read:#54d2e6;--reticle-ok:#3dd7a6;--reticle-bad:#ff7a7a;\n --reticle-font:\"Inter\",system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;\n --reticle-serif:\"IBM Plex Serif\",Georgia,\"Times New Roman\",serif;\n position:fixed;left:50%;right:auto;bottom:20px;box-sizing:border-box;\n width:384px;height:468px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);\n display:flex;flex-direction:column;overflow:hidden;text-align:left;z-index:2147483647;pointer-events:none;\n font-family:var(--reticle-font);font-size:13px;line-height:1.5;color:var(--reticle-fg);-webkit-font-smoothing:antialiased;\n background:linear-gradient(180deg,var(--reticle-bg),var(--reticle-bg2));\n -webkit-backdrop-filter:blur(24px) saturate(1.5);backdrop-filter:blur(24px) saturate(1.5);\n border:1px solid var(--reticle-line);border-radius:20px;\n box-shadow:0 28px 70px -18px rgba(0,0,0,.66),0 0 0 1px rgba(0,0,0,.35),inset 0 1px 0 rgba(255,255,255,.07),0 0 54px -22px var(--reticle-accent);\n opacity:0;transform:translateX(-50%) translateY(14px) scale(.985);\n transition:opacity .3s ease,transform .42s cubic-bezier(.16,1,.3,1),height .42s cubic-bezier(.16,1,.3,1),border-radius .42s ease,box-shadow .35s ease;}\n[data-reticle-overlay][data-reticle-state=\"paused\"] [data-reticle-hud]{--reticle-accent:#f6b44c;--reticle-accent-soft:rgba(246,180,76,.16);}\n[data-reticle-overlay][data-reticle-state=\"ended\"] [data-reticle-hud]{--reticle-accent:#3dd7a6;--reticle-accent-soft:rgba(61,215,166,.14);}\n[data-reticle-hud]::before{content:\"\";position:absolute;inset:0;border-radius:inherit;pointer-events:none;\n background:radial-gradient(130% 90% at 50% 0%,var(--reticle-accent-soft),transparent 60%);}\n[data-reticle-hud]>*{position:relative;}\n[data-reticle-hud][data-on=\"1\"]{opacity:1;transform:translateX(-50%) translateY(0) scale(1);}\n/* Click-through: the glassy panel itself never blocks the app \u2014 only its interactive controls\n capture clicks (buttons / inputs), so a human can click straight through the HUD to the page.\n The log auto-scrolls, so it stays click-through too (drag-scroll is traded for click-through). */\n[data-reticle-hud] button,[data-reticle-hud] input,[data-reticle-hud] textarea,\n[data-reticle-hud] select,[data-reticle-hud] [contenteditable]{pointer-events:auto;}\n/* When minimised to a pill, the whole bar is the (single) click target to restore. */\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud][data-on=\"1\"]{pointer-events:auto;}\n[data-reticle-hud] .reticle-hud-head{display:flex;align-items:center;gap:8px;flex:none;\n padding:12px 12px 12px 15px;border-bottom:1px solid var(--reticle-line2);}\n[data-reticle-hud] .reticle-dot{width:9px;height:9px;border-radius:50%;flex:none;background:var(--reticle-accent);\n animation:reticle-breathe 2.6s ease-in-out infinite;}\n@keyframes reticle-breathe{0%,100%{box-shadow:0 0 0 0 var(--reticle-accent),0 0 7px 1px var(--reticle-accent);opacity:.85}\n 50%{box-shadow:0 0 0 4px var(--reticle-accent-soft),0 0 15px 3px var(--reticle-accent);opacity:1}}\n[data-reticle-hud] .reticle-brand{font-family:var(--reticle-serif);font-weight:500;font-size:15px;letter-spacing:.01em;color:var(--reticle-fg);}\n[data-reticle-hud] .reticle-head-sp{flex:1;}\n[data-reticle-hud] .reticle-live{display:none;flex:1;min-width:0;color:var(--reticle-muted);font-size:12.5px;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}\n[data-reticle-hud] .reticle-maxhint{display:none;flex:none;color:var(--reticle-faint);font-size:13px;line-height:1;}\n[data-reticle-hud] .reticle-act-strip{flex:none;padding:7px 15px;border-bottom:1px solid var(--reticle-line2);background:rgba(0,0,0,.14);}\n[data-reticle-hud] .reticle-act{display:block;color:var(--reticle-muted);font-size:11.5px;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}\n[data-reticle-hud] [data-reticle-min-btn]{flex:none;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;\n width:26px;height:26px;border-radius:8px;border:1px solid var(--reticle-line);background:rgba(255,255,255,.04);\n color:var(--reticle-muted);font-size:15px;line-height:1;transition:background .15s,color .15s,transform .1s;}\n[data-reticle-hud] [data-reticle-min-btn]:hover{color:var(--reticle-fg);background:rgba(255,255,255,.08);}\n[data-reticle-hud] [data-reticle-min-btn]:active{transform:scale(.94);}\n[data-reticle-hud] .reticle-pass{color:var(--reticle-ok);}[data-reticle-hud] .reticle-fail{color:var(--reticle-bad);}\n[data-reticle-hud] .reticle-tally{flex:none;display:inline-flex;align-items:center;gap:8px;font-size:11.5px;\n font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:.01em;}\n[data-reticle-hud] .reticle-tally[hidden]{display:none;}\n[data-reticle-hud] .reticle-tally .reticle-t-pass{color:var(--reticle-ok);}\n[data-reticle-hud] .reticle-tally .reticle-t-fail{color:var(--reticle-bad);}\n[data-reticle-hud] .reticle-tally [data-z=\"1\"]{opacity:.4;}\n@keyframes reticle-tally-pop{0%{transform:scale(1)}38%{transform:scale(1.3)}100%{transform:scale(1)}}\n[data-reticle-hud] .reticle-tally [data-bump=\"1\"]{display:inline-block;animation:reticle-tally-pop .36s cubic-bezier(.16,1,.3,1);}\n[data-reticle-hud] .reticle-chip{display:none;flex:none;font-size:9px;font-weight:600;letter-spacing:.08em;\n padding:2px 7px;border-radius:6px;vertical-align:middle;}\n[data-reticle-hud] .reticle-chip[data-mode=\"reading\"]{display:inline-block;color:var(--reticle-read);\n background:rgba(84,210,230,.12);border:1px solid rgba(84,210,230,.32);}\n[data-reticle-hud] .reticle-chip[data-mode=\"acting\"]{display:inline-block;color:var(--reticle-accent);\n background:var(--reticle-accent-soft);border:1px solid var(--reticle-accent);}\n[data-reticle-hud] .reticle-chip[data-mode=\"idle\"]{display:none;}\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud]{height:50px;border-radius:25px;cursor:pointer;}\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-hud-head{border-bottom:none;height:50px;padding:0 12px 0 16px;}\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-brand,\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-chip,\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-head-sp,\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] [data-reticle-min-btn],\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-ctl,\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-badge,\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-act-strip,\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] [data-reticle-log],\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] [data-reticle-foot],\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-banner{display:none;}\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-live{display:block;}\n[data-reticle-overlay][data-reticle-min=\"1\"] [data-reticle-hud] .reticle-maxhint{display:inline-flex;}\n[data-reticle-mode=\"reading\"] [data-reticle-glow][data-on=\"1\"]{\n box-shadow:inset 0 0 0 3px rgba(34,211,238,.9),inset 0 0 28px 6px rgba(34,211,238,.4);}\n[data-reticle-mode=\"reading\"] [data-reticle-ring]{border-color:#22d3ee;\n box-shadow:0 0 0 3px rgba(34,211,238,.25);}\n[data-reticle-overlay][data-reticle-throttled=\"1\"] [data-reticle-glow][data-on=\"1\"]{\n box-shadow:inset 0 0 0 3px rgba(251,191,36,.9),inset 0 0 28px 6px rgba(251,191,36,.45);}\n[data-reticle-overlay][data-reticle-throttled=\"1\"] [data-reticle-hud]{--reticle-accent:#fbbf24;--reticle-accent-soft:rgba(251,191,36,.16);}\n\n[data-reticle-log]{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;\n gap:7px;padding:12px 14px;scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent;}\n[data-reticle-log]::-webkit-scrollbar{width:9px;}\n[data-reticle-log]::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:9px;border:2px solid transparent;background-clip:content-box;}\n[data-reticle-log]::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.26);background-clip:content-box;}\n[data-reticle-log-row]{display:flex;align-items:baseline;gap:8px;font-size:12px;line-height:1.45;\n animation:reticle-row-in .26s cubic-bezier(.16,1,.3,1);}\n@keyframes reticle-row-in{from{opacity:0;transform:translateY(5px);}to{opacity:1;transform:none;}}\n[data-reticle-log-ts]{flex:none;color:var(--reticle-faint);font-size:10px;font-variant-numeric:tabular-nums;padding-top:1px;}\n[data-reticle-log] .reticle-log-text{flex:1;min-width:0;color:#d6dae4;overflow-wrap:anywhere;word-break:break-word;}\n[data-reticle-log] .reticle-res{flex:none;font-weight:700;}\n[data-reticle-log-row][data-kind=\"human\"]{align-self:flex-end;max-width:88%;\n background:var(--reticle-accent-soft);border:1px solid var(--reticle-accent);border-radius:13px 13px 4px 13px;padding:6px 11px;}\n[data-reticle-log-row][data-kind=\"human\"] [data-reticle-log-ts]{display:none;}\n[data-reticle-log-row][data-kind=\"human\"] .reticle-log-text{color:var(--reticle-fg);}\n\n\n[data-reticle-hud] .reticle-ctl{pointer-events:auto;cursor:pointer;flex:none;display:inline-flex;align-items:center;justify-content:center;\n height:26px;padding:0 11px;border-radius:8px;border:1px solid var(--reticle-line);background:rgba(255,255,255,.04);\n color:var(--reticle-muted);font-family:var(--reticle-font);font-size:11px;font-weight:500;letter-spacing:.01em;line-height:1;\n transition:background .15s,color .15s,border-color .15s,transform .1s;}\n[data-reticle-hud] .reticle-ctl:hover{color:var(--reticle-fg);background:rgba(255,255,255,.09);}\n[data-reticle-hud] .reticle-ctl:active{transform:scale(.95);}\n[data-reticle-hud] .reticle-ctl:disabled{opacity:.35;cursor:default;}\n[data-reticle-hud] [data-reticle-end]{color:#ff9aa2;border-color:rgba(255,107,107,.22);}\n[data-reticle-hud] [data-reticle-end]:hover{color:#ff7a7a;border-color:rgba(255,107,107,.5);background:rgba(255,107,107,.1);}\n[data-reticle-hud] .reticle-badge{display:none;align-items:center;flex:none;font-weight:600;letter-spacing:.1em;font-size:9px;\n color:var(--reticle-accent);border:1px solid var(--reticle-accent);background:var(--reticle-accent-soft);padding:2px 8px;border-radius:999px;}\n[data-reticle-overlay][data-reticle-state=\"paused\"] [data-reticle-badge]{display:inline-flex;}\n[data-reticle-hud] [data-reticle-foot]{flex:none;padding:10px 12px 12px;border-top:1px solid var(--reticle-line2);background:rgba(0,0,0,.16);}\n[data-reticle-hud] .reticle-composer{display:flex;align-items:flex-end;gap:6px;background:rgba(255,255,255,.05);\n border:1px solid var(--reticle-line);border-radius:14px;padding:5px 6px 5px 14px;transition:border-color .15s,box-shadow .15s;}\n[data-reticle-hud] .reticle-composer:focus-within{border-color:var(--reticle-accent);box-shadow:0 0 0 3px var(--reticle-accent-soft);}\n[data-reticle-hud] .reticle-msg{flex:1;min-width:0;pointer-events:auto;background:transparent;border:none;outline:none;resize:none;\n color:var(--reticle-fg);font-family:var(--reticle-font);font-size:13px;line-height:18px;height:18px;min-height:18px;max-height:96px;\n padding:5px 0;overflow-y:auto;}\n[data-reticle-hud] .reticle-msg::placeholder{color:var(--reticle-faint);}\n[data-reticle-hud] .reticle-msg:disabled{opacity:.5;}\n[data-reticle-hud] .reticle-send{flex:none;width:30px;height:30px;padding:0;border-radius:10px;border:none;cursor:pointer;pointer-events:auto;\n background:var(--reticle-accent);color:#0b0d14;display:inline-flex;align-items:center;justify-content:center;transition:filter .15s,transform .1s;}\n[data-reticle-hud] .reticle-send svg{display:block;}\n[data-reticle-hud] .reticle-send:hover{filter:brightness(1.12);}\n[data-reticle-hud] .reticle-send:active{transform:scale(.9);}\n[data-reticle-hud] .reticle-send:disabled{opacity:.4;cursor:default;}\n[data-reticle-hud] .reticle-banner{display:none;flex:none;padding:8px 15px;color:var(--reticle-accent);\n font-size:11.5px;font-weight:500;border-bottom:1px solid var(--reticle-line2);background:var(--reticle-accent-soft);}\n[data-reticle-overlay][data-reticle-state=\"ended\"] [data-reticle-banner]{display:block;}\n/* Export row: hidden during a live session; revealed when ended so the run can be copied/saved. */\n[data-reticle-hud] .reticle-export{display:none;align-items:center;gap:8px;margin-top:9px;}\n[data-reticle-overlay][data-reticle-state=\"ended\"] [data-reticle-hud] .reticle-export{display:flex;}\n[data-reticle-hud] .reticle-export-msg{color:var(--reticle-ok);font-size:11px;opacity:0;transition:opacity .15s;}\n[data-reticle-hud] .reticle-export-msg[data-show=\"1\"]{opacity:1;}\n[data-reticle-overlay][data-reticle-state=\"paused\"] [data-reticle-glow][data-on=\"1\"]{animation:none;\n box-shadow:inset 0 0 0 3px rgba(246,180,76,.9),inset 0 0 30px 6px rgba(246,180,76,.4);}\n[data-reticle-overlay][data-reticle-state=\"ended\"] [data-reticle-glow][data-on=\"1\"]{animation:none;\n box-shadow:inset 0 0 0 2px rgba(61,215,166,.55);}\n/* Handoff tones tell the human the agent's mode at a glance. waiting = calm teal \"your turn\" (no\n alarm); ask = amber \"answer me\" with a pulse; warn = amber \"agent crashed\" with a pulse. Each leads\n the banner with an icon and overrides the calm ended-green accent. */\n[data-reticle-overlay][data-reticle-tone=\"waiting\"] [data-reticle-hud]{--reticle-accent:#38bdf8;--reticle-accent-soft:rgba(56,189,248,.16);}\n[data-reticle-overlay][data-reticle-tone=\"waiting\"] [data-reticle-banner]{font-weight:600;color:#7dd3fc;}\n[data-reticle-overlay][data-reticle-tone=\"waiting\"] [data-reticle-banner]::before{content:\"\\270B \";}\n[data-reticle-overlay][data-reticle-tone=\"waiting\"] [data-reticle-glow][data-on=\"1\"]{animation:none;\n box-shadow:inset 0 0 0 2px rgba(56,189,248,.5);}\n[data-reticle-overlay][data-reticle-tone=\"ask\"] [data-reticle-hud],\n[data-reticle-overlay][data-reticle-tone=\"warn\"] [data-reticle-hud]{--reticle-accent:#fb923c;--reticle-accent-soft:rgba(251,146,60,.18);}\n[data-reticle-overlay][data-reticle-tone=\"ask\"] [data-reticle-banner],\n[data-reticle-overlay][data-reticle-tone=\"warn\"] [data-reticle-banner]{font-weight:600;color:#fdba74;}\n[data-reticle-overlay][data-reticle-tone=\"ask\"] [data-reticle-banner]::before{content:\"\\2753 \";}\n[data-reticle-overlay][data-reticle-tone=\"warn\"] [data-reticle-banner]::before{content:\"\\26A0\\FE0F \";}\n[data-reticle-overlay][data-reticle-tone=\"ask\"] [data-reticle-glow][data-on=\"1\"],\n[data-reticle-overlay][data-reticle-tone=\"warn\"] [data-reticle-glow][data-on=\"1\"]{animation:reticle-warn-pulse 1.5s ease-in-out infinite;\n box-shadow:inset 0 0 0 2px rgba(251,146,60,.7);}\n@keyframes reticle-warn-pulse{0%,100%{box-shadow:inset 0 0 0 2px rgba(251,146,60,.32);}\n 50%{box-shadow:inset 0 0 0 3px rgba(251,146,60,.85),inset 0 0 26px 5px rgba(251,146,60,.34);}}\n/* Replay-a-flow row: the human re-runs a saved flow with no agent. Hidden until flows are pushed.\n Bounded + self-scrolling: it sits between the flex:1 log and the flex:none composer, so without a\n height cap a long flow list would squeeze the log to nothing and push the message input past the\n panel's overflow:hidden clip. flex:none + max-height + overflow-y keep the log and input always\n visible; extra flow chips scroll inside this section instead of growing the panel. */\n[data-reticle-hud] .reticle-flows{display:none;flex:none;flex-wrap:wrap;align-content:flex-start;gap:6px;\n padding:9px 12px;border-top:1px solid var(--reticle-line2);max-height:88px;overflow-y:auto;overscroll-behavior:contain;}\n[data-reticle-hud] .reticle-flows[data-has=\"1\"]{display:flex;}\n[data-reticle-hud] .reticle-flows::-webkit-scrollbar{width:9px;}\n[data-reticle-hud] .reticle-flows::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:9px;border:2px solid transparent;background-clip:content-box;}\n[data-reticle-hud] .reticle-flows-cap{flex:0 0 100%;margin-bottom:1px;color:var(--reticle-faint);font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;}\n[data-reticle-hud] .reticle-flow{pointer-events:auto;cursor:pointer;display:inline-flex;align-items:center;gap:5px;height:24px;padding:0 10px;\n border-radius:7px;border:1px solid var(--reticle-line);background:rgba(255,255,255,.04);color:var(--reticle-muted);\n font-family:var(--reticle-font);font-size:11px;font-weight:500;transition:background .15s,color .15s,border-color .15s,transform .1s;}\n[data-reticle-hud] .reticle-flow:hover{color:var(--reticle-fg);background:var(--reticle-accent-soft);border-color:var(--reticle-accent);}\n[data-reticle-hud] .reticle-flow:active{transform:scale(.95);}\n";
7
+ //# sourceMappingURL=presenter-styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-styles.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-styles.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,aAAa,4ylBA6GV,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { LOG_CSS } from './presenter-log.js';
2
+ import { CONTROLS_CSS } from './presenter-controls.js';
3
+ /**
4
+ * All presenter overlay CSS — the glow border, synthetic cursor/ring/ripple, and the glassy HUD.
5
+ * Split out of presenter.ts so that file stays a cohesive controller under the size cap; this is
6
+ * pure style data (no behavior). LOG_CSS + CONTROLS_CSS are composed in at the end as before.
7
+ */
8
+ export const PRESENTER_CSS = `
9
+ @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Serif:wght@400;500&family=Inter:wght@400;450;500;600&display=swap");
10
+ [data-reticle-glow]{position:fixed;inset:0;pointer-events:none;z-index:2147483600;opacity:0;
11
+ transition:opacity .25s ease;box-shadow:inset 0 0 0 3px rgba(99,102,241,.9),inset 0 0 28px 6px rgba(99,102,241,.45);}
12
+ [data-reticle-glow][data-on="1"]{opacity:1;animation:reticle-pulse 1.6s ease-in-out infinite;}
13
+ [data-reticle-glow][data-on="1"][data-busy="1"]{animation:reticle-shimmer 1.1s ease-in-out infinite;}
14
+ @keyframes reticle-pulse{0%,100%{box-shadow:inset 0 0 0 3px rgba(99,102,241,.9),inset 0 0 22px 4px rgba(99,102,241,.35)}
15
+ 50%{box-shadow:inset 0 0 0 3px rgba(124,127,242,1),inset 0 0 40px 10px rgba(99,102,241,.6)}}
16
+ @keyframes reticle-shimmer{0%,100%{box-shadow:inset 0 0 0 3px rgba(124,127,242,1),inset 0 0 34px 8px rgba(99,102,241,.55)}
17
+ 50%{box-shadow:inset 0 0 0 3px rgba(140,142,255,1),inset 0 0 48px 12px rgba(99,102,241,.7)}}
18
+ [data-reticle-cursor]{position:fixed;top:0;left:0;width:22px;height:22px;margin:-11px 0 0 -11px;
19
+ border:2px solid #6366f1;border-radius:50%;background:rgba(99,102,241,.25);pointer-events:none;
20
+ z-index:2147483646;opacity:0;transition:transform .32s cubic-bezier(.22,1,.36,1),opacity .2s ease;}
21
+ [data-reticle-cursor][data-on="1"]{opacity:1;}
22
+ [data-reticle-cursor]::after{content:"";position:absolute;inset:7px;border-radius:50%;background:#6366f1;}
23
+ [data-reticle-ripple]{position:fixed;width:14px;height:14px;margin:-7px 0 0 -7px;border-radius:50%;
24
+ background:rgba(99,102,241,.5);pointer-events:none;z-index:2147483645;animation:reticle-ripple .5s ease-out forwards;}
25
+ @keyframes reticle-ripple{from{transform:scale(.4);opacity:.8}to{transform:scale(5);opacity:0}}
26
+ [data-reticle-ring]{position:fixed;pointer-events:none;z-index:2147483644;border:2px solid #22c55e;border-radius:8px;
27
+ box-shadow:0 0 0 3px rgba(34,197,94,.25);opacity:0;transition:opacity .15s ease;}
28
+ [data-reticle-ring][data-on="1"]{opacity:1;}
29
+ [data-reticle-hud]{
30
+ --reticle-accent:#7c83ff;--reticle-accent-soft:rgba(124,131,255,.16);
31
+ --reticle-bg:rgba(13,15,22,.80);--reticle-bg2:rgba(19,22,32,.74);
32
+ --reticle-fg:#e9ebf2;--reticle-muted:#9aa0b2;--reticle-faint:#6a7186;
33
+ --reticle-line:rgba(255,255,255,.09);--reticle-line2:rgba(255,255,255,.05);
34
+ --reticle-read:#54d2e6;--reticle-ok:#3dd7a6;--reticle-bad:#ff7a7a;
35
+ --reticle-font:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
36
+ --reticle-serif:"IBM Plex Serif",Georgia,"Times New Roman",serif;
37
+ position:fixed;left:50%;right:auto;bottom:20px;box-sizing:border-box;
38
+ width:384px;height:468px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);
39
+ display:flex;flex-direction:column;overflow:hidden;text-align:left;z-index:2147483647;pointer-events:none;
40
+ font-family:var(--reticle-font);font-size:13px;line-height:1.5;color:var(--reticle-fg);-webkit-font-smoothing:antialiased;
41
+ background:linear-gradient(180deg,var(--reticle-bg),var(--reticle-bg2));
42
+ -webkit-backdrop-filter:blur(24px) saturate(1.5);backdrop-filter:blur(24px) saturate(1.5);
43
+ border:1px solid var(--reticle-line);border-radius:20px;
44
+ box-shadow:0 28px 70px -18px rgba(0,0,0,.66),0 0 0 1px rgba(0,0,0,.35),inset 0 1px 0 rgba(255,255,255,.07),0 0 54px -22px var(--reticle-accent);
45
+ opacity:0;transform:translateX(-50%) translateY(14px) scale(.985);
46
+ transition:opacity .3s ease,transform .42s cubic-bezier(.16,1,.3,1),height .42s cubic-bezier(.16,1,.3,1),border-radius .42s ease,box-shadow .35s ease;}
47
+ [data-reticle-overlay][data-reticle-state="paused"] [data-reticle-hud]{--reticle-accent:#f6b44c;--reticle-accent-soft:rgba(246,180,76,.16);}
48
+ [data-reticle-overlay][data-reticle-state="ended"] [data-reticle-hud]{--reticle-accent:#3dd7a6;--reticle-accent-soft:rgba(61,215,166,.14);}
49
+ [data-reticle-hud]::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
50
+ background:radial-gradient(130% 90% at 50% 0%,var(--reticle-accent-soft),transparent 60%);}
51
+ [data-reticle-hud]>*{position:relative;}
52
+ [data-reticle-hud][data-on="1"]{opacity:1;transform:translateX(-50%) translateY(0) scale(1);}
53
+ /* Click-through: the glassy panel itself never blocks the app — only its interactive controls
54
+ capture clicks (buttons / inputs), so a human can click straight through the HUD to the page.
55
+ The log auto-scrolls, so it stays click-through too (drag-scroll is traded for click-through). */
56
+ [data-reticle-hud] button,[data-reticle-hud] input,[data-reticle-hud] textarea,
57
+ [data-reticle-hud] select,[data-reticle-hud] [contenteditable]{pointer-events:auto;}
58
+ /* When minimised to a pill, the whole bar is the (single) click target to restore. */
59
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud][data-on="1"]{pointer-events:auto;}
60
+ [data-reticle-hud] .reticle-hud-head{display:flex;align-items:center;gap:8px;flex:none;
61
+ padding:12px 12px 12px 15px;border-bottom:1px solid var(--reticle-line2);}
62
+ [data-reticle-hud] .reticle-dot{width:9px;height:9px;border-radius:50%;flex:none;background:var(--reticle-accent);
63
+ animation:reticle-breathe 2.6s ease-in-out infinite;}
64
+ @keyframes reticle-breathe{0%,100%{box-shadow:0 0 0 0 var(--reticle-accent),0 0 7px 1px var(--reticle-accent);opacity:.85}
65
+ 50%{box-shadow:0 0 0 4px var(--reticle-accent-soft),0 0 15px 3px var(--reticle-accent);opacity:1}}
66
+ [data-reticle-hud] .reticle-brand{font-family:var(--reticle-serif);font-weight:500;font-size:15px;letter-spacing:.01em;color:var(--reticle-fg);}
67
+ [data-reticle-hud] .reticle-head-sp{flex:1;}
68
+ [data-reticle-hud] .reticle-live{display:none;flex:1;min-width:0;color:var(--reticle-muted);font-size:12.5px;
69
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
70
+ [data-reticle-hud] .reticle-maxhint{display:none;flex:none;color:var(--reticle-faint);font-size:13px;line-height:1;}
71
+ [data-reticle-hud] .reticle-act-strip{flex:none;padding:7px 15px;border-bottom:1px solid var(--reticle-line2);background:rgba(0,0,0,.14);}
72
+ [data-reticle-hud] .reticle-act{display:block;color:var(--reticle-muted);font-size:11.5px;
73
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
74
+ [data-reticle-hud] [data-reticle-min-btn]{flex:none;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
75
+ width:26px;height:26px;border-radius:8px;border:1px solid var(--reticle-line);background:rgba(255,255,255,.04);
76
+ color:var(--reticle-muted);font-size:15px;line-height:1;transition:background .15s,color .15s,transform .1s;}
77
+ [data-reticle-hud] [data-reticle-min-btn]:hover{color:var(--reticle-fg);background:rgba(255,255,255,.08);}
78
+ [data-reticle-hud] [data-reticle-min-btn]:active{transform:scale(.94);}
79
+ [data-reticle-hud] .reticle-pass{color:var(--reticle-ok);}[data-reticle-hud] .reticle-fail{color:var(--reticle-bad);}
80
+ [data-reticle-hud] .reticle-tally{flex:none;display:inline-flex;align-items:center;gap:8px;font-size:11.5px;
81
+ font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:.01em;}
82
+ [data-reticle-hud] .reticle-tally[hidden]{display:none;}
83
+ [data-reticle-hud] .reticle-tally .reticle-t-pass{color:var(--reticle-ok);}
84
+ [data-reticle-hud] .reticle-tally .reticle-t-fail{color:var(--reticle-bad);}
85
+ [data-reticle-hud] .reticle-tally [data-z="1"]{opacity:.4;}
86
+ @keyframes reticle-tally-pop{0%{transform:scale(1)}38%{transform:scale(1.3)}100%{transform:scale(1)}}
87
+ [data-reticle-hud] .reticle-tally [data-bump="1"]{display:inline-block;animation:reticle-tally-pop .36s cubic-bezier(.16,1,.3,1);}
88
+ [data-reticle-hud] .reticle-chip{display:none;flex:none;font-size:9px;font-weight:600;letter-spacing:.08em;
89
+ padding:2px 7px;border-radius:6px;vertical-align:middle;}
90
+ [data-reticle-hud] .reticle-chip[data-mode="reading"]{display:inline-block;color:var(--reticle-read);
91
+ background:rgba(84,210,230,.12);border:1px solid rgba(84,210,230,.32);}
92
+ [data-reticle-hud] .reticle-chip[data-mode="acting"]{display:inline-block;color:var(--reticle-accent);
93
+ background:var(--reticle-accent-soft);border:1px solid var(--reticle-accent);}
94
+ [data-reticle-hud] .reticle-chip[data-mode="idle"]{display:none;}
95
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud]{height:50px;border-radius:25px;cursor:pointer;}
96
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-hud-head{border-bottom:none;height:50px;padding:0 12px 0 16px;}
97
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-brand,
98
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-chip,
99
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-head-sp,
100
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] [data-reticle-min-btn],
101
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-ctl,
102
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-badge,
103
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-act-strip,
104
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] [data-reticle-log],
105
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] [data-reticle-foot],
106
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-banner{display:none;}
107
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-live{display:block;}
108
+ [data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-maxhint{display:inline-flex;}
109
+ [data-reticle-mode="reading"] [data-reticle-glow][data-on="1"]{
110
+ box-shadow:inset 0 0 0 3px rgba(34,211,238,.9),inset 0 0 28px 6px rgba(34,211,238,.4);}
111
+ [data-reticle-mode="reading"] [data-reticle-ring]{border-color:#22d3ee;
112
+ box-shadow:0 0 0 3px rgba(34,211,238,.25);}
113
+ [data-reticle-overlay][data-reticle-throttled="1"] [data-reticle-glow][data-on="1"]{
114
+ box-shadow:inset 0 0 0 3px rgba(251,191,36,.9),inset 0 0 28px 6px rgba(251,191,36,.45);}
115
+ [data-reticle-overlay][data-reticle-throttled="1"] [data-reticle-hud]{--reticle-accent:#fbbf24;--reticle-accent-soft:rgba(251,191,36,.16);}
116
+ ${LOG_CSS}
117
+ ${CONTROLS_CSS}`;
118
+ //# sourceMappingURL=presenter-styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-styles.js","sourceRoot":"","sources":["../../src/presenter/presenter-styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4G3B,OAAO;EACP,YAAY,EAAE,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type LogResult } from './presenter-log.js';
2
+ /** Running verdict counts the header tally shows — the testing score the human watches grow. */
3
+ export interface TallyCounts {
4
+ passes: number;
5
+ fails: number;
6
+ }
7
+ /** Count pass/fail verdicts across the run log. Pure — no DOM, unit-testable. */
8
+ export declare function countVerdicts(runLog: {
9
+ result?: LogResult;
10
+ }[]): TallyCounts;
11
+ /**
12
+ * Paint the live verdict tally (✓N ✗M) into the header element from the run log. Hidden until the
13
+ * first verdict lands; the side that just GREW gets a one-shot pop so the human FEELS the green (or
14
+ * red) arrive — the score they watch climb as the agent verifies. Returns the new counts so the
15
+ * caller tracks what grew for the next paint. Split out of presenter.ts to keep the controller lean.
16
+ */
17
+ export declare function renderTally(el: HTMLElement | undefined, runLog: {
18
+ result?: LogResult;
19
+ }[], prev: TallyCounts): TallyCounts;
20
+ //# sourceMappingURL=presenter-tally.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-tally.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-tally.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEhE,gGAAgG;AAChG,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,EAAE,GAAG,WAAW,CAQ3E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,WAAW,GAAG,SAAS,EAC3B,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,EAAE,EAChC,IAAI,EAAE,WAAW,GAChB,WAAW,CAgBb"}
@@ -0,0 +1,38 @@
1
+ import { LOG_RESULT } from './presenter-log.js';
2
+ /** Count pass/fail verdicts across the run log. Pure — no DOM, unit-testable. */
3
+ export function countVerdicts(runLog) {
4
+ let passes = 0;
5
+ let fails = 0;
6
+ for (const e of runLog) {
7
+ if (e.result === LOG_RESULT.PASS)
8
+ passes += 1;
9
+ else if (e.result === LOG_RESULT.FAIL)
10
+ fails += 1;
11
+ }
12
+ return { passes, fails };
13
+ }
14
+ /**
15
+ * Paint the live verdict tally (✓N ✗M) into the header element from the run log. Hidden until the
16
+ * first verdict lands; the side that just GREW gets a one-shot pop so the human FEELS the green (or
17
+ * red) arrive — the score they watch climb as the agent verifies. Returns the new counts so the
18
+ * caller tracks what grew for the next paint. Split out of presenter.ts to keep the controller lean.
19
+ */
20
+ export function renderTally(el, runLog, prev) {
21
+ const next = countVerdicts(runLog);
22
+ if (el === undefined)
23
+ return next;
24
+ if (next.passes === 0 && next.fails === 0) {
25
+ el.setAttribute('hidden', '');
26
+ return next;
27
+ }
28
+ const bumpPass = next.passes > prev.passes ? ' data-bump="1"' : '';
29
+ const bumpFail = next.fails > prev.fails ? ' data-bump="1"' : '';
30
+ const dimP = next.passes === 0 ? ' data-z="1"' : '';
31
+ const dimF = next.fails === 0 ? ' data-z="1"' : '';
32
+ el.removeAttribute('hidden');
33
+ el.innerHTML =
34
+ `<span class="reticle-t-pass"${dimP}${bumpPass}>✓ ${String(next.passes)}</span>` +
35
+ `<span class="reticle-t-fail"${dimF}${bumpFail}>✗ ${String(next.fails)}</span>`;
36
+ return next;
37
+ }
38
+ //# sourceMappingURL=presenter-tally.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-tally.js","sourceRoot":"","sources":["../../src/presenter/presenter-tally.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAkB,MAAM,oBAAoB,CAAC;AAQhE,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,MAAgC;IAC5D,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,IAAI;YAAE,MAAM,IAAI,CAAC,CAAC;aACzC,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,IAAI;YAAE,KAAK,IAAI,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CACzB,EAA2B,EAC3B,MAAgC,EAChC,IAAiB;IAEjB,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;QAC1C,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IACnD,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC7B,EAAE,CAAC,SAAS;QACV,+BAA+B,IAAI,GAAG,QAAQ,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS;YAChF,+BAA+B,IAAI,GAAG,QAAQ,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;IAClF,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function actionVerb(action: string): string;
2
+ //# sourceMappingURL=presenter-verbs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-verbs.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-verbs.ts"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAwBjD"}
@@ -0,0 +1,29 @@
1
+ // Present-tense verb for an action label in the presenter HUD (cursor status + act-log row).
2
+ // Presenter-only UI copy — never a wire string. Shared by presenter.ts (cursor) and reticle.ts
3
+ // (act-log row) so the two stay in lockstep.
4
+ export function actionVerb(action) {
5
+ switch (action) {
6
+ case 'click':
7
+ case 'dblclick':
8
+ return 'Clicking';
9
+ case 'fill':
10
+ case 'type':
11
+ return 'Typing into';
12
+ case 'hover':
13
+ return 'Hovering';
14
+ case 'select':
15
+ return 'Selecting';
16
+ case 'submit':
17
+ return 'Submitting';
18
+ case 'check':
19
+ case 'uncheck':
20
+ return 'Toggling';
21
+ case 'upload':
22
+ return 'Uploading to';
23
+ case 'drag':
24
+ return 'Dragging';
25
+ default:
26
+ return action;
27
+ }
28
+ }
29
+ //# sourceMappingURL=presenter-verbs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presenter-verbs.js","sourceRoot":"","sources":["../../src/presenter/presenter-verbs.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,+FAA+F;AAC/F,6CAA6C;AAC7C,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO,CAAC;QACb,KAAK,UAAU;YACb,OAAO,UAAU,CAAC;QACpB,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM;YACT,OAAO,aAAa,CAAC;QACvB,KAAK,OAAO;YACV,OAAO,UAAU,CAAC;QACpB,KAAK,QAAQ;YACX,OAAO,WAAW,CAAC;QACrB,KAAK,QAAQ;YACX,OAAO,YAAY,CAAC;QACtB,KAAK,OAAO,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,UAAU,CAAC;QACpB,KAAK,QAAQ;YACX,OAAO,cAAc,CAAC;QACxB,KAAK,MAAM;YACT,OAAO,UAAU,CAAC;QACpB;YACE,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC"}