@reticlehq/browser 2.8.0 → 2.9.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.
- package/NOTICE +7 -0
- package/dist/actions/actions-dom.js +23 -15
- package/dist/actions/actions.d.ts +17 -0
- package/dist/actions/actions.js +132 -29
- package/dist/actions/synthetic-input.d.ts +9 -0
- package/dist/actions/synthetic-input.js +40 -0
- package/dist/commands/commands.js +11 -1
- package/dist/connect-options.d.ts +9 -9
- package/dist/dom/a11y.d.ts +9 -0
- package/dist/dom/a11y.js +19 -0
- package/dist/dom/dom-ignore.d.ts +19 -6
- package/dist/dom/dom-ignore.js +20 -13
- package/dist/dom/query.d.ts +2 -2
- package/dist/dom/query.js +85 -45
- package/dist/dom/snapshot.d.ts +5 -0
- package/dist/dom/snapshot.js +34 -0
- package/dist/dom/source.d.ts +14 -0
- package/dist/dom/source.js +16 -0
- package/dist/observers/install-all.js +4 -1
- package/dist/observers/ipc.d.ts +16 -0
- package/dist/observers/ipc.js +19 -1
- package/dist/observers/network.d.ts +8 -0
- package/dist/observers/network.js +24 -3
- package/dist/observers/state.js +21 -2
- package/dist/presenter/presenter-brand.d.ts +24 -7
- package/dist/presenter/presenter-brand.js +23 -6
- package/dist/presenter/presenter-config.d.ts +102 -9
- package/dist/presenter/presenter-config.js +94 -8
- package/dist/presenter/presenter-controls.d.ts +10 -10
- package/dist/presenter/presenter-controls.js +175 -85
- package/dist/presenter/presenter-dock-layout.d.ts +6 -0
- package/dist/presenter/presenter-dock-layout.js +170 -0
- package/dist/presenter/presenter-drag.d.ts +48 -0
- package/dist/presenter/presenter-drag.js +198 -0
- package/dist/presenter/presenter-effects.d.ts +1 -1
- package/dist/presenter/presenter-effects.js +1 -1
- package/dist/presenter/presenter-glow.d.ts +5 -5
- package/dist/presenter/presenter-glow.js +7 -7
- package/dist/presenter/presenter-heroicons-data.d.ts +41 -0
- package/dist/presenter/presenter-heroicons-data.js +38 -0
- package/dist/presenter/presenter-hud-chrome.d.ts +17 -0
- package/dist/presenter/presenter-hud-chrome.js +41 -0
- package/dist/presenter/presenter-icons.d.ts +44 -0
- package/dist/presenter/presenter-icons.js +100 -0
- package/dist/presenter/presenter-log.d.ts +27 -5
- package/dist/presenter/presenter-log.js +114 -28
- package/dist/presenter/presenter-report-copy.d.ts +83 -0
- package/dist/presenter/presenter-report-copy.js +127 -0
- package/dist/presenter/presenter-report-styles.d.ts +7 -0
- package/dist/presenter/presenter-report-styles.js +102 -0
- package/dist/presenter/presenter-report.d.ts +23 -0
- package/dist/presenter/presenter-report.js +217 -0
- package/dist/presenter/presenter-run-state.d.ts +1 -1
- package/dist/presenter/presenter-settings-styles.d.ts +2 -0
- package/dist/presenter/presenter-settings-styles.js +153 -0
- package/dist/presenter/presenter-settings.d.ts +82 -0
- package/dist/presenter/presenter-settings.js +494 -0
- package/dist/presenter/presenter-shell-styles.d.ts +1 -0
- package/dist/presenter/presenter-shell-styles.js +375 -0
- package/dist/presenter/presenter-shell.d.ts +48 -0
- package/dist/presenter/presenter-shell.js +408 -0
- package/dist/presenter/presenter-styles.d.ts +9 -4
- package/dist/presenter/presenter-styles.js +61 -125
- package/dist/presenter/presenter-tally.d.ts +8 -11
- package/dist/presenter/presenter-tally.js +48 -23
- package/dist/presenter/presenter-test-helpers.d.ts +1 -1
- package/dist/presenter/presenter-test-helpers.js +1 -1
- package/dist/presenter/presenter-verbs.js +2 -2
- package/dist/presenter/presenter-workspace.d.ts +15 -0
- package/dist/presenter/presenter-workspace.js +180 -0
- package/dist/presenter/presenter.d.ts +15 -10
- package/dist/presenter/presenter.js +194 -46
- package/dist/reticle.d.ts +2 -2
- package/dist/reticle.js +23 -19
- package/dist/review/annotator-styles.d.ts +6 -0
- package/dist/review/annotator-styles.js +81 -0
- package/dist/review/annotator.d.ts +29 -17
- package/dist/review/annotator.js +477 -146
- package/package.json +7 -4
|
@@ -1,137 +1,73 @@
|
|
|
1
1
|
import { LOG_CSS } from './presenter-log.js';
|
|
2
2
|
import { CONTROLS_CSS } from './presenter-controls.js';
|
|
3
|
+
import { SHELL_CSS } from './presenter-shell-styles.js';
|
|
4
|
+
import { SETTINGS_CSS } from './presenter-settings-styles.js';
|
|
5
|
+
import { HUD_CHROME_CSS, HUD_LOG_WELL_CSS } from './presenter-hud-chrome.js';
|
|
6
|
+
import { REPORT_CSS } from './presenter-report-styles.js';
|
|
3
7
|
/**
|
|
4
|
-
* All presenter overlay CSS
|
|
5
|
-
* Split
|
|
6
|
-
* pure style data (no behavior). LOG_CSS + CONTROLS_CSS are composed in at the end as before.
|
|
8
|
+
* All presenter overlay CSS - glow border, synthetic cursor/ring/ripple, and the floating HUD shell.
|
|
9
|
+
* Split across shell-styles + controls + log modules so each file stays under the size cap.
|
|
7
10
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* The presenter overlay's stacking layer. Exported because the annotator has to sit ABOVE it: the
|
|
13
|
+
* overlay holds the page blocker, and anything below this number is covered by that shield - which
|
|
14
|
+
* is what buried the annotate composer and made its Cancel/Add buttons unclickable.
|
|
15
|
+
*/
|
|
16
|
+
export const Z_OVERLAY = 2147483600;
|
|
12
17
|
export const PRESENTER_CSS = `
|
|
13
|
-
[data-reticle-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
[data-reticle-overlay]{position:fixed;inset:0;pointer-events:none;z-index:${String(Z_OVERLAY)};}
|
|
19
|
+
/**
|
|
20
|
+
* The session glow: the page itself says an agent is here, and BREATHES while it is working.
|
|
21
|
+
*
|
|
22
|
+
* A white 1px hairline with no animation replaced the accent-coloured, pulsing border, and the one
|
|
23
|
+
* signal you could read without looking at the HUD - "something is driving my app right now" -
|
|
24
|
+
* disappeared with it. The accent follows the HUD's own swatch (--reticle-mark-accent, set on the
|
|
25
|
+
* overlay root), so glow, cursor and dock stay one colour.
|
|
26
|
+
*/
|
|
27
|
+
[data-reticle-glow]{position:fixed;inset:0;pointer-events:none;z-index:${String(Z_OVERLAY)};opacity:0;
|
|
28
|
+
--reticle-glow:var(--reticle-state,var(--reticle-mark-accent,#6366f1));
|
|
29
|
+
transition:opacity .25s ease;
|
|
30
|
+
box-shadow:inset 0 0 0 2px color-mix(in srgb,var(--reticle-glow) 70%,transparent),
|
|
31
|
+
inset 0 0 22px 4px color-mix(in srgb,var(--reticle-glow) 26%,transparent);}
|
|
32
|
+
[data-reticle-glow][data-on="1"]{opacity:1;animation:reticle-pulse 2.4s ease-in-out infinite;}
|
|
16
33
|
[data-reticle-glow][data-on="1"][data-busy="1"]{animation:reticle-shimmer 1.1s ease-in-out infinite;}
|
|
17
|
-
@keyframes reticle-pulse{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
50%{box-shadow:inset 0 0 0
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
@keyframes reticle-pulse{
|
|
35
|
+
0%,100%{box-shadow:inset 0 0 0 2px color-mix(in srgb,var(--reticle-glow) 60%,transparent),
|
|
36
|
+
inset 0 0 18px 3px color-mix(in srgb,var(--reticle-glow) 18%,transparent)}
|
|
37
|
+
50%{box-shadow:inset 0 0 0 2px color-mix(in srgb,var(--reticle-glow) 80%,transparent),
|
|
38
|
+
inset 0 0 30px 6px color-mix(in srgb,var(--reticle-glow) 32%,transparent)}}
|
|
39
|
+
@keyframes reticle-shimmer{
|
|
40
|
+
0%,100%{box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--reticle-glow) 85%,transparent),
|
|
41
|
+
inset 0 0 30px 7px color-mix(in srgb,var(--reticle-glow) 42%,transparent)}
|
|
42
|
+
50%{box-shadow:inset 0 0 0 3px var(--reticle-glow),
|
|
43
|
+
inset 0 0 46px 12px color-mix(in srgb,var(--reticle-glow) 58%,transparent)}}
|
|
44
|
+
[data-reticle-overlay][data-reticle-reduce-motion="1"] [data-reticle-glow][data-on="1"]{animation:none;}
|
|
45
|
+
/* The page glow is the one signal that paints over the USER's app, so it is theirs to switch off.
|
|
46
|
+
Every other signal - dot, panel, capsule, FAB halo - stays. */
|
|
47
|
+
[data-reticle-overlay][data-reticle-ambient-glow="0"] [data-reticle-glow]{display:none;}
|
|
48
|
+
[data-reticle-cursor]{position:fixed;top:0;left:0;width:20px;height:20px;margin:-10px 0 0 -10px;
|
|
49
|
+
border:2px solid #fafafa;border-radius:50%;background:rgba(255,255,255,.12);pointer-events:none;
|
|
23
50
|
z-index:2147483646;opacity:0;transition:transform .32s cubic-bezier(.22,1,.36,1),opacity .2s ease;}
|
|
24
51
|
[data-reticle-cursor][data-on="1"]{opacity:1;}
|
|
25
|
-
[data-reticle-cursor]::after{content:"";position:absolute;inset:
|
|
26
|
-
[data-reticle-ripple]{position:fixed;width:
|
|
27
|
-
background:rgba(
|
|
28
|
-
@keyframes reticle-ripple{from{transform:scale(.
|
|
29
|
-
[data-reticle-ring]{position:fixed;pointer-events:none;z-index:2147483644;border:
|
|
30
|
-
box-shadow:
|
|
52
|
+
[data-reticle-cursor]::after{content:"";position:absolute;inset:6px;border-radius:50%;background:#fafafa;}
|
|
53
|
+
[data-reticle-ripple]{position:fixed;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;
|
|
54
|
+
background:rgba(255,255,255,.35);pointer-events:none;z-index:2147483645;animation:reticle-ripple .45s ease-out forwards;}
|
|
55
|
+
@keyframes reticle-ripple{from{transform:scale(.5);opacity:.7}to{transform:scale(4);opacity:0}}
|
|
56
|
+
[data-reticle-ring]{position:fixed;pointer-events:none;z-index:2147483644;border:1px solid rgba(255,255,255,.55);border-radius:6px;
|
|
57
|
+
box-shadow:none;opacity:0;transition:opacity .15s ease;}
|
|
31
58
|
[data-reticle-ring][data-on="1"]{opacity:1;}
|
|
32
|
-
[data-reticle-
|
|
33
|
-
|
|
34
|
-
--reticle-bg:rgba(13,15,22,.92);--reticle-bg2:rgba(19,22,32,.88);
|
|
35
|
-
--reticle-fg:#e9ebf2;--reticle-muted:#9aa0b2;--reticle-faint:#6a7186;
|
|
36
|
-
--reticle-line:rgba(255,255,255,.09);--reticle-line2:rgba(255,255,255,.05);
|
|
37
|
-
--reticle-read:#54d2e6;--reticle-ok:#3dd7a6;--reticle-bad:#ff7a7a;
|
|
38
|
-
--reticle-font:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
|
|
39
|
-
position:fixed;left:50%;right:auto;bottom:20px;box-sizing:border-box;
|
|
40
|
-
width:384px;height:468px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);
|
|
41
|
-
display:flex;flex-direction:column;overflow:hidden;text-align:left;z-index:2147483647;pointer-events:none;
|
|
42
|
-
font-family:var(--reticle-font);font-size:13px;line-height:1.5;color:var(--reticle-fg);-webkit-font-smoothing:antialiased;
|
|
43
|
-
background:linear-gradient(180deg,var(--reticle-bg),var(--reticle-bg2));
|
|
44
|
-
/* No backdrop-filter here, deliberately. blur(24px) on this panel was measured as the single most
|
|
45
|
-
expensive thing the whole SDK does: a backdrop blur must re-sample everything behind it whenever
|
|
46
|
-
that content changes, and on a page repainting at 60fps that is continuous full-panel work. On
|
|
47
|
-
the hostile fixture it cost +4.0pp of main thread — five times the rest of the presenter, and
|
|
48
|
-
more than every observer combined. Removing it took total main-thread time from 2.15s to 1.67s
|
|
49
|
-
over an 8s window. The panel background is ~85% opaque, so the glass effect it bought was
|
|
50
|
-
marginal. If you want it back, add it here and expect to pay that. */
|
|
51
|
-
border:1px solid var(--reticle-line);border-radius:20px;
|
|
52
|
-
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);
|
|
53
|
-
opacity:0;transform:translateX(-50%) translateY(14px) scale(.985);
|
|
54
|
-
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;}
|
|
55
|
-
[data-reticle-overlay][data-reticle-state="paused"] [data-reticle-hud]{--reticle-accent:#f6b44c;--reticle-accent-soft:rgba(246,180,76,.16);}
|
|
56
|
-
[data-reticle-overlay][data-reticle-state="ended"] [data-reticle-hud]{--reticle-accent:#3dd7a6;--reticle-accent-soft:rgba(61,215,166,.14);}
|
|
57
|
-
[data-reticle-hud]::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
|
|
58
|
-
background:radial-gradient(130% 90% at 50% 0%,var(--reticle-accent-soft),transparent 60%);}
|
|
59
|
-
[data-reticle-hud]>*{position:relative;}
|
|
60
|
-
[data-reticle-hud][data-on="1"]{opacity:1;transform:translateX(-50%) translateY(0) scale(1);}
|
|
61
|
-
/* Click-through: the glassy panel itself never blocks the app — only its interactive controls
|
|
62
|
-
capture clicks (buttons / inputs), so a human can click straight through the HUD to the page.
|
|
63
|
-
The log auto-scrolls, so it stays click-through too (drag-scroll is traded for click-through). */
|
|
64
|
-
[data-reticle-hud] button,[data-reticle-hud] input,[data-reticle-hud] textarea,
|
|
65
|
-
[data-reticle-hud] select,[data-reticle-hud] [contenteditable]{pointer-events:auto;}
|
|
66
|
-
/* When minimised to a pill, the whole bar is the (single) click target to restore. */
|
|
67
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud][data-on="1"]{pointer-events:auto;}
|
|
68
|
-
[data-reticle-hud] .reticle-hud-head{display:flex;align-items:center;gap:8px;flex:none;
|
|
69
|
-
padding:12px 12px 12px 15px;border-bottom:1px solid var(--reticle-line2);}
|
|
70
|
-
/* Brand block: both marks always in the DOM, CSS picks one off data-reticle-min (see below) so the
|
|
71
|
-
collapsed/expanded swap needs no JS state. Artwork paints with currentColor, so it inherits
|
|
72
|
-
--reticle-fg and reads correctly on any HUD surface instead of baking in the export's #FAFAFA. */
|
|
73
|
-
[data-reticle-hud] .reticle-brand{display:inline-flex;align-items:center;flex:none;color:var(--reticle-fg);}
|
|
74
|
-
[data-reticle-hud] .reticle-mark{display:none;height:18px;width:auto;flex:none;}
|
|
75
|
-
[data-reticle-hud] .reticle-wordmark{display:block;height:16px;width:auto;flex:none;}
|
|
76
|
-
/* Visually hidden, still announced — the marks are aria-hidden artwork, this names the HUD. */
|
|
77
|
-
[data-reticle-hud] .reticle-brand-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
|
|
78
|
-
overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;}
|
|
79
|
-
[data-reticle-hud] .reticle-head-sp{flex:1;}
|
|
80
|
-
[data-reticle-hud] .reticle-live{display:none;flex:1;min-width:0;color:var(--reticle-muted);font-size:12.5px;
|
|
81
|
-
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
82
|
-
[data-reticle-hud] .reticle-maxhint{display:none;flex:none;color:var(--reticle-faint);font-size:13px;line-height:1;}
|
|
83
|
-
[data-reticle-hud] .reticle-act-strip{flex:none;padding:7px 15px;border-bottom:1px solid var(--reticle-line2);background:rgba(0,0,0,.14);}
|
|
84
|
-
[data-reticle-hud] .reticle-act{display:block;color:var(--reticle-muted);font-size:11.5px;
|
|
85
|
-
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
|
|
86
|
-
[data-reticle-hud] [data-reticle-min-btn]{flex:none;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
|
|
87
|
-
width:26px;height:26px;border-radius:8px;border:1px solid var(--reticle-line);background:rgba(255,255,255,.04);
|
|
88
|
-
color:var(--reticle-muted);font-size:15px;line-height:1;transition:background .15s,color .15s,transform .1s;}
|
|
89
|
-
[data-reticle-hud] [data-reticle-min-btn]:hover{color:var(--reticle-fg);background:rgba(255,255,255,.08);}
|
|
90
|
-
[data-reticle-hud] [data-reticle-min-btn]:active{transform:scale(.94);}
|
|
91
|
-
[data-reticle-hud] .reticle-pass{color:var(--reticle-ok);}[data-reticle-hud] .reticle-fail{color:var(--reticle-bad);}
|
|
92
|
-
[data-reticle-hud] .reticle-tally{flex:none;display:inline-flex;align-items:center;gap:8px;font-size:11.5px;
|
|
93
|
-
font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:.01em;}
|
|
94
|
-
[data-reticle-hud] .reticle-tally[hidden]{display:none;}
|
|
95
|
-
[data-reticle-hud] .reticle-tally .reticle-t-pass{color:var(--reticle-ok);}
|
|
96
|
-
[data-reticle-hud] .reticle-tally .reticle-t-fail{color:var(--reticle-bad);}
|
|
97
|
-
[data-reticle-hud] .reticle-tally [data-z="1"]{opacity:.4;}
|
|
98
|
-
@keyframes reticle-tally-pop{0%{transform:scale(1)}38%{transform:scale(1.3)}100%{transform:scale(1)}}
|
|
99
|
-
[data-reticle-hud] .reticle-tally [data-bump="1"]{display:inline-block;animation:reticle-tally-pop .36s cubic-bezier(.16,1,.3,1);}
|
|
100
|
-
[data-reticle-hud] .reticle-chip{display:none;flex:none;font-size:9px;font-weight:600;letter-spacing:.08em;
|
|
101
|
-
padding:2px 7px;border-radius:6px;vertical-align:middle;}
|
|
102
|
-
[data-reticle-hud] .reticle-chip[data-mode="reading"]{display:inline-block;color:var(--reticle-read);
|
|
103
|
-
background:rgba(84,210,230,.12);border:1px solid rgba(84,210,230,.32);}
|
|
104
|
-
[data-reticle-hud] .reticle-chip[data-mode="acting"]{display:inline-block;color:var(--reticle-accent);
|
|
105
|
-
background:var(--reticle-accent-soft);border:1px solid var(--reticle-accent);}
|
|
106
|
-
[data-reticle-hud] .reticle-chip[data-mode="idle"]{display:none;}
|
|
107
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud]{height:50px;border-radius:25px;cursor:pointer;}
|
|
108
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-hud-head{border-bottom:none;height:50px;padding:0 12px 0 16px;}
|
|
109
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-chip,
|
|
110
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-head-sp,
|
|
111
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] [data-reticle-min-btn],
|
|
112
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-ctl,
|
|
113
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-badge,
|
|
114
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-act-strip,
|
|
115
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] [data-reticle-log],
|
|
116
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] [data-reticle-foot],
|
|
117
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-banner{display:none;}
|
|
118
|
-
/* Collapsed to a pill: mark only, beside the dot. Expanded: the full wordmark. */
|
|
119
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-wordmark{display:none;}
|
|
120
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-mark{display:block;}
|
|
121
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-live{display:block;}
|
|
122
|
-
[data-reticle-overlay][data-reticle-min="1"] [data-reticle-hud] .reticle-maxhint{display:inline-flex;}
|
|
123
|
-
[data-reticle-mode="reading"] [data-reticle-glow][data-on="1"]{
|
|
124
|
-
box-shadow:inset 0 0 0 3px rgba(34,211,238,.9),inset 0 0 28px 6px rgba(34,211,238,.4);}
|
|
125
|
-
[data-reticle-mode="reading"] [data-reticle-ring]{border-color:#22d3ee;
|
|
126
|
-
box-shadow:0 0 0 3px rgba(34,211,238,.25);}
|
|
59
|
+
[data-reticle-mode="reading"] [data-reticle-glow][data-on="1"]{box-shadow:inset 0 0 0 2px rgba(255,255,255,.22);}
|
|
60
|
+
[data-reticle-mode="reading"] [data-reticle-ring]{border-color:rgba(255,255,255,.7);box-shadow:none;}
|
|
127
61
|
[data-reticle-overlay][data-reticle-throttled="1"] [data-reticle-glow][data-on="1"]{
|
|
128
|
-
box-shadow:inset 0 0 0
|
|
129
|
-
[data-reticle-overlay]
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
62
|
+
box-shadow:inset 0 0 0 2px rgba(255,255,255,.18);}
|
|
63
|
+
[data-reticle-overlay] .reticle-hi-icon,
|
|
64
|
+
[data-reticle-overlay] .reticle-sl-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1;flex-shrink:0;color:inherit;overflow:visible;}
|
|
65
|
+
[data-reticle-overlay] .reticle-hi-icon svg,
|
|
66
|
+
[data-reticle-overlay] .reticle-sl-icon svg{display:block;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;overflow:visible;}
|
|
67
|
+
${HUD_CHROME_CSS}
|
|
68
|
+
${HUD_LOG_WELL_CSS}
|
|
69
|
+
${SHELL_CSS}
|
|
70
|
+
${SETTINGS_CSS}
|
|
71
|
+
${REPORT_CSS}
|
|
136
72
|
${LOG_CSS}
|
|
137
73
|
${CONTROLS_CSS}`;
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { type LogResult } from './presenter-log.js';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Paint the live verdict tally into a YouTube-style segmented pill (pass | fail).
|
|
4
|
+
*/
|
|
5
|
+
export declare function renderTally(el: HTMLElement | undefined, runLog: {
|
|
6
|
+
result?: LogResult;
|
|
7
|
+
}[], prev: TallyCounts): TallyCounts;
|
|
8
|
+
/** Running verdict counts the header tally shows - the testing score the human watches grow. */
|
|
3
9
|
export interface TallyCounts {
|
|
4
10
|
passes: number;
|
|
5
11
|
fails: number;
|
|
6
12
|
}
|
|
7
|
-
/** Count pass/fail verdicts across the run log. Pure
|
|
13
|
+
/** Count pass/fail verdicts across the run log. Pure - no DOM, unit-testable. */
|
|
8
14
|
export declare function countVerdicts(runLog: {
|
|
9
15
|
result?: LogResult;
|
|
10
16
|
}[]): 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;
|
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
import { LOG_RESULT } from './presenter-log.js';
|
|
2
|
-
|
|
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
|
-
}
|
|
2
|
+
import { PresenterIcon, PRESENTER_ICON_SIZE, hiIcon } from './presenter-icons.js';
|
|
14
3
|
/**
|
|
15
|
-
* Paint the live verdict tally
|
|
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.
|
|
4
|
+
* Paint the live verdict tally into a YouTube-style segmented pill (pass | fail).
|
|
19
5
|
*/
|
|
20
6
|
export function renderTally(el, runLog, prev) {
|
|
21
7
|
const next = countVerdicts(runLog);
|
|
@@ -23,15 +9,54 @@ export function renderTally(el, runLog, prev) {
|
|
|
23
9
|
return next;
|
|
24
10
|
if (0 === next.passes && 0 === next.fails) {
|
|
25
11
|
el.setAttribute('hidden', '');
|
|
12
|
+
el.replaceChildren();
|
|
26
13
|
return next;
|
|
27
14
|
}
|
|
28
|
-
const
|
|
29
|
-
const bumpFail = next.fails > prev.fails ? ' data-bump="1"' : '';
|
|
30
|
-
const dimP = 0 === next.passes ? ' data-z="1"' : '';
|
|
31
|
-
const dimF = 0 === next.fails ? ' data-z="1"' : '';
|
|
15
|
+
const doc = el.ownerDocument;
|
|
32
16
|
el.removeAttribute('hidden');
|
|
33
|
-
el.
|
|
34
|
-
|
|
35
|
-
|
|
17
|
+
el.className = 'reticle-tally reticle-pill-group reticle-head-ctl';
|
|
18
|
+
el.replaceChildren();
|
|
19
|
+
const pass = doc.createElement('span');
|
|
20
|
+
pass.className = 'reticle-t-pass reticle-pill-segment';
|
|
21
|
+
if (0 === next.passes)
|
|
22
|
+
pass.setAttribute('data-z', '1');
|
|
23
|
+
if (next.passes > prev.passes)
|
|
24
|
+
pass.setAttribute('data-bump', '1');
|
|
25
|
+
pass.append(hiIcon(PresenterIcon.CHECK, PRESENTER_ICON_SIZE.TALLY));
|
|
26
|
+
if (next.passes > 0) {
|
|
27
|
+
const passN = doc.createElement('span');
|
|
28
|
+
passN.className = 'reticle-pill-count';
|
|
29
|
+
passN.textContent = String(next.passes);
|
|
30
|
+
pass.append(passN);
|
|
31
|
+
}
|
|
32
|
+
const sep = doc.createElement('span');
|
|
33
|
+
sep.className = 'reticle-pill-sep';
|
|
34
|
+
sep.setAttribute('aria-hidden', 'true');
|
|
35
|
+
const fail = doc.createElement('span');
|
|
36
|
+
fail.className = 'reticle-t-fail reticle-pill-segment';
|
|
37
|
+
if (0 === next.fails)
|
|
38
|
+
fail.setAttribute('data-z', '1');
|
|
39
|
+
if (next.fails > prev.fails)
|
|
40
|
+
fail.setAttribute('data-bump', '1');
|
|
41
|
+
fail.append(hiIcon(PresenterIcon.REMOVE, PRESENTER_ICON_SIZE.TALLY));
|
|
42
|
+
if (next.fails > 0) {
|
|
43
|
+
const failN = doc.createElement('span');
|
|
44
|
+
failN.className = 'reticle-pill-count';
|
|
45
|
+
failN.textContent = String(next.fails);
|
|
46
|
+
fail.append(failN);
|
|
47
|
+
}
|
|
48
|
+
el.append(pass, sep, fail);
|
|
36
49
|
return next;
|
|
37
50
|
}
|
|
51
|
+
/** Count pass/fail verdicts across the run log. Pure - no DOM, unit-testable. */
|
|
52
|
+
export function countVerdicts(runLog) {
|
|
53
|
+
let passes = 0;
|
|
54
|
+
let fails = 0;
|
|
55
|
+
for (const e of runLog) {
|
|
56
|
+
if (e.result === LOG_RESULT.PASS)
|
|
57
|
+
passes += 1;
|
|
58
|
+
else if (e.result === LOG_RESULT.FAIL)
|
|
59
|
+
fails += 1;
|
|
60
|
+
}
|
|
61
|
+
return { passes, fails };
|
|
62
|
+
}
|
|
@@ -3,7 +3,7 @@ export declare const FAST_IDLE_MS = 20;
|
|
|
3
3
|
export declare const FAST_FADE_MS = 5;
|
|
4
4
|
export declare const flush: () => Promise<void>;
|
|
5
5
|
export declare const wait: (ms: number) => Promise<void>;
|
|
6
|
-
/** Poll a predicate until true or timeout
|
|
6
|
+
/** Poll a predicate until true or timeout - robust to real-timer lateness under load (no flake). */
|
|
7
7
|
export declare const until: (pred: () => boolean, ms?: number) => Promise<boolean>;
|
|
8
8
|
export declare const dataOn: () => string | null;
|
|
9
9
|
export declare const dataBusy: () => string | null;
|
|
@@ -3,7 +3,7 @@ export const FAST_IDLE_MS = 20;
|
|
|
3
3
|
export const FAST_FADE_MS = 5;
|
|
4
4
|
export const flush = () => new Promise((r) => setTimeout(r, 0));
|
|
5
5
|
export const wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
6
|
-
/** Poll a predicate until true or timeout
|
|
6
|
+
/** Poll a predicate until true or timeout - robust to real-timer lateness under load (no flake). */
|
|
7
7
|
export const until = async (pred, ms = 1000) => {
|
|
8
8
|
const t0 = Date.now();
|
|
9
9
|
while (!pred()) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Present-tense verb for an action label in the presenter HUD (cursor status + act-log row).
|
|
2
|
-
// Presenter-only UI copy
|
|
2
|
+
// Presenter-only UI copy - never a wire string. Shared by presenter.ts (cursor) and reticle.ts
|
|
3
3
|
// (act-log row) so the two stay in lockstep.
|
|
4
4
|
//
|
|
5
5
|
// The CASES are wire values though, and they are core's ActionType. Spelled as free strings here,
|
|
6
|
-
// a rename in core left this switch silently falling through to `default`
|
|
6
|
+
// a rename in core left this switch silently falling through to `default` - which returns the raw
|
|
7
7
|
// action name, so the HUD degrades to "webmcp Save" instead of a verb and nothing fails.
|
|
8
8
|
import { ActionType } from '@reticlehq/core';
|
|
9
9
|
export function actionVerb(action) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Read the Vite-injected repo root, when present. */
|
|
2
|
+
export declare function readWorkspaceRoot(): string | undefined;
|
|
3
|
+
/** Last path segment for compact display (Codex/Cursor-style chip). */
|
|
4
|
+
export declare function workspaceFolderLabel(root: string): string;
|
|
5
|
+
/** Project id from the URL lease stamp, when present. */
|
|
6
|
+
export declare function readProjectIdFromUrl(): string | undefined;
|
|
7
|
+
export declare function workspaceSummary(): {
|
|
8
|
+
folder: string;
|
|
9
|
+
root?: string;
|
|
10
|
+
projectId?: string;
|
|
11
|
+
};
|
|
12
|
+
/** Workspace chip + detail menu - sits above the composer row. */
|
|
13
|
+
export declare function workspaceRowHtml(): string;
|
|
14
|
+
export declare function paintWorkspace(root: HTMLElement): void;
|
|
15
|
+
export declare function mountWorkspaceSelector(root: HTMLElement): () => void;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { RETICLE_ROOT_GLOBAL, RETICLE_URL_PARAM } from '@reticlehq/core';
|
|
2
|
+
import { PresenterIcon, PRESENTER_ICON_SIZE, hiIconHtml } from './presenter-icons.js';
|
|
3
|
+
const WORKSPACE_BTN_ATTR = 'data-reticle-workspace-btn';
|
|
4
|
+
const WORKSPACE_MENU_ATTR = 'data-reticle-workspace-menu';
|
|
5
|
+
const WORKSPACE_NAME_ATTR = 'data-reticle-workspace-name';
|
|
6
|
+
const WORKSPACE_PATH_ATTR = 'data-reticle-workspace-path';
|
|
7
|
+
const WORKSPACE_PROJECT_ATTR = 'data-reticle-workspace-project';
|
|
8
|
+
const WORKSPACE_COPY_ATTR = 'data-reticle-workspace-copy';
|
|
9
|
+
const WORKSPACE_LABEL = 'Workspace';
|
|
10
|
+
const PROJECT_LABEL = 'Project';
|
|
11
|
+
const COPY_PATH_LABEL = 'Copy path';
|
|
12
|
+
const COPIED_PATH_LABEL = 'Copied';
|
|
13
|
+
const WORKSPACE_FALLBACK = 'This page';
|
|
14
|
+
/** Read the Vite-injected repo root, when present. */
|
|
15
|
+
export function readWorkspaceRoot() {
|
|
16
|
+
const value = globalThis[RETICLE_ROOT_GLOBAL];
|
|
17
|
+
return 'string' === typeof value && value.length > 0 ? value : undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Last path segment for compact display (Codex/Cursor-style chip). */
|
|
20
|
+
export function workspaceFolderLabel(root) {
|
|
21
|
+
const normalized = root.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
22
|
+
const parts = normalized.split('/').filter((part) => part.length > 0);
|
|
23
|
+
const last = parts[parts.length - 1];
|
|
24
|
+
return last !== undefined && last.length > 0 ? last : WORKSPACE_FALLBACK;
|
|
25
|
+
}
|
|
26
|
+
/** Project id from the URL lease stamp, when present. */
|
|
27
|
+
export function readProjectIdFromUrl() {
|
|
28
|
+
if ('undefined' === typeof window)
|
|
29
|
+
return undefined;
|
|
30
|
+
const id = new URLSearchParams(window.location.search).get(RETICLE_URL_PARAM.PROJECT);
|
|
31
|
+
return id !== null && id.length > 0 ? id : undefined;
|
|
32
|
+
}
|
|
33
|
+
export function workspaceSummary() {
|
|
34
|
+
const root = readWorkspaceRoot();
|
|
35
|
+
const projectId = readProjectIdFromUrl();
|
|
36
|
+
const folder = root !== undefined ? workspaceFolderLabel(root) : WORKSPACE_FALLBACK;
|
|
37
|
+
if (root === undefined && projectId === undefined)
|
|
38
|
+
return { folder };
|
|
39
|
+
const out = { folder };
|
|
40
|
+
if (root !== undefined)
|
|
41
|
+
out.root = root;
|
|
42
|
+
if (projectId !== undefined)
|
|
43
|
+
out.projectId = projectId;
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/** Workspace chip + detail menu - sits above the composer row. */
|
|
47
|
+
export function workspaceRowHtml() {
|
|
48
|
+
const folderIcon = hiIconHtml(PresenterIcon.LAYOUT, PRESENTER_ICON_SIZE.HELP);
|
|
49
|
+
const caret = hiIconHtml(PresenterIcon.CARET_DOWN, PRESENTER_ICON_SIZE.HELP);
|
|
50
|
+
const copyIcon = hiIconHtml(PresenterIcon.COPY, PRESENTER_ICON_SIZE.HELP);
|
|
51
|
+
return `<div class="reticle-workspace-wrap">
|
|
52
|
+
<button type="button" class="reticle-workspace" ${WORKSPACE_BTN_ATTR} aria-haspopup="true" aria-expanded="false" title="${WORKSPACE_LABEL}">
|
|
53
|
+
<span class="reticle-workspace-icon" aria-hidden="true">${folderIcon}</span>
|
|
54
|
+
<span class="reticle-workspace-name" ${WORKSPACE_NAME_ATTR}>${WORKSPACE_FALLBACK}</span>
|
|
55
|
+
<span class="reticle-workspace-caret" aria-hidden="true">${caret}</span>
|
|
56
|
+
</button>
|
|
57
|
+
<div class="reticle-workspace-menu" ${WORKSPACE_MENU_ATTR} role="dialog" aria-label="${WORKSPACE_LABEL}" aria-hidden="true" hidden>
|
|
58
|
+
<div class="reticle-workspace-menu-head">
|
|
59
|
+
<div class="reticle-workspace-menu-title">${WORKSPACE_LABEL}</div>
|
|
60
|
+
<button type="button" class="reticle-workspace-copy" ${WORKSPACE_COPY_ATTR} title="${COPY_PATH_LABEL}" aria-label="${COPY_PATH_LABEL}">${copyIcon}</button>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="reticle-workspace-menu-row"><span class="reticle-workspace-menu-k">Folder</span><span class="reticle-workspace-menu-v" data-reticle-workspace-folder></span></div>
|
|
63
|
+
<div class="reticle-workspace-menu-row"><span class="reticle-workspace-menu-k">Path</span><span class="reticle-workspace-menu-v reticle-workspace-menu-path" ${WORKSPACE_PATH_ATTR}></span></div>
|
|
64
|
+
<div class="reticle-workspace-menu-row" data-reticle-workspace-project-row hidden><span class="reticle-workspace-menu-k">${PROJECT_LABEL}</span><span class="reticle-workspace-menu-v" ${WORKSPACE_PROJECT_ATTR}></span></div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>`;
|
|
67
|
+
}
|
|
68
|
+
export function paintWorkspace(root) {
|
|
69
|
+
const summary = workspaceSummary();
|
|
70
|
+
// Nothing to say - no injected repo root, no leased project id - so the chip says nothing. It
|
|
71
|
+
// used to render its fallback, "This page", which names no workspace and is exactly as true of
|
|
72
|
+
// every page. The chip earns its slot only when it can tell you WHICH checkout is being driven.
|
|
73
|
+
const wrap = root.querySelector('.reticle-workspace-wrap');
|
|
74
|
+
if (wrap instanceof HTMLElement) {
|
|
75
|
+
const known = summary.root !== undefined || summary.projectId !== undefined;
|
|
76
|
+
wrap.toggleAttribute('hidden', !known);
|
|
77
|
+
}
|
|
78
|
+
const chipName = root.querySelector(`[${WORKSPACE_BTN_ATTR}] [${WORKSPACE_NAME_ATTR}]`);
|
|
79
|
+
if (chipName instanceof HTMLElement)
|
|
80
|
+
chipName.textContent = summary.folder;
|
|
81
|
+
const folderEl = root.querySelector('[data-reticle-workspace-folder]');
|
|
82
|
+
if (folderEl instanceof HTMLElement)
|
|
83
|
+
folderEl.textContent = summary.folder;
|
|
84
|
+
const pathEl = root.querySelector(`[${WORKSPACE_PATH_ATTR}]`);
|
|
85
|
+
if (pathEl instanceof HTMLElement) {
|
|
86
|
+
pathEl.textContent = summary.root ?? '-';
|
|
87
|
+
pathEl.title = summary.root ?? '';
|
|
88
|
+
}
|
|
89
|
+
const projectEl = root.querySelector(`[${WORKSPACE_PROJECT_ATTR}]`);
|
|
90
|
+
const projectRow = root.querySelector('[data-reticle-workspace-project-row]');
|
|
91
|
+
const copyBtn = root.querySelector(`[${WORKSPACE_COPY_ATTR}]`);
|
|
92
|
+
if (summary.projectId !== undefined) {
|
|
93
|
+
projectRow?.removeAttribute('hidden');
|
|
94
|
+
if (projectEl instanceof HTMLElement)
|
|
95
|
+
projectEl.textContent = summary.projectId;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
projectRow?.setAttribute('hidden', '');
|
|
99
|
+
if (projectEl instanceof HTMLElement)
|
|
100
|
+
projectEl.textContent = '';
|
|
101
|
+
}
|
|
102
|
+
if (copyBtn instanceof HTMLButtonElement) {
|
|
103
|
+
copyBtn.disabled = summary.root === undefined;
|
|
104
|
+
}
|
|
105
|
+
const btn = root.querySelector(`[${WORKSPACE_BTN_ATTR}]`);
|
|
106
|
+
if (btn instanceof HTMLElement && summary.root !== undefined) {
|
|
107
|
+
btn.title = `${WORKSPACE_LABEL}: ${summary.root}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export function mountWorkspaceSelector(root) {
|
|
111
|
+
paintWorkspace(root);
|
|
112
|
+
const btn = root.querySelector(`[${WORKSPACE_BTN_ATTR}]`);
|
|
113
|
+
const menu = root.querySelector(`[${WORKSPACE_MENU_ATTR}]`);
|
|
114
|
+
const copyBtn = root.querySelector(`[${WORKSPACE_COPY_ATTR}]`);
|
|
115
|
+
if (!(btn instanceof HTMLElement) || !(menu instanceof HTMLElement))
|
|
116
|
+
return () => undefined;
|
|
117
|
+
const close = () => {
|
|
118
|
+
menu.setAttribute('aria-hidden', 'true');
|
|
119
|
+
menu.setAttribute('hidden', '');
|
|
120
|
+
btn.setAttribute('aria-expanded', 'false');
|
|
121
|
+
};
|
|
122
|
+
const open = () => {
|
|
123
|
+
paintWorkspace(root);
|
|
124
|
+
menu.removeAttribute('hidden');
|
|
125
|
+
menu.setAttribute('aria-hidden', 'false');
|
|
126
|
+
btn.setAttribute('aria-expanded', 'true');
|
|
127
|
+
};
|
|
128
|
+
const toggle = () => {
|
|
129
|
+
if ('true' === menu.getAttribute('aria-hidden') || menu.hasAttribute('hidden'))
|
|
130
|
+
open();
|
|
131
|
+
else
|
|
132
|
+
close();
|
|
133
|
+
};
|
|
134
|
+
const onBtnClick = (e) => {
|
|
135
|
+
e.stopPropagation();
|
|
136
|
+
toggle();
|
|
137
|
+
};
|
|
138
|
+
const onDocPointer = (e) => {
|
|
139
|
+
const target = e.target;
|
|
140
|
+
if (!(target instanceof Node))
|
|
141
|
+
return;
|
|
142
|
+
if (btn.contains(target) || menu.contains(target))
|
|
143
|
+
return;
|
|
144
|
+
close();
|
|
145
|
+
};
|
|
146
|
+
const onKeyDown = (e) => {
|
|
147
|
+
if ('Escape' !== e.key)
|
|
148
|
+
return;
|
|
149
|
+
if ('true' === menu.getAttribute('aria-hidden') || menu.hasAttribute('hidden'))
|
|
150
|
+
return;
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
e.stopPropagation();
|
|
153
|
+
close();
|
|
154
|
+
};
|
|
155
|
+
const onCopy = (e) => {
|
|
156
|
+
e.stopPropagation();
|
|
157
|
+
const path = workspaceSummary().root;
|
|
158
|
+
if (path === undefined)
|
|
159
|
+
return;
|
|
160
|
+
void navigator.clipboard?.writeText(path);
|
|
161
|
+
if (copyBtn instanceof HTMLButtonElement) {
|
|
162
|
+
const prior = copyBtn.title;
|
|
163
|
+
copyBtn.title = COPIED_PATH_LABEL;
|
|
164
|
+
window.setTimeout(() => {
|
|
165
|
+
copyBtn.title = prior;
|
|
166
|
+
}, 1200);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
btn.addEventListener('click', onBtnClick);
|
|
170
|
+
menu.addEventListener('pointerdown', (e) => e.stopPropagation());
|
|
171
|
+
copyBtn?.addEventListener('click', onCopy);
|
|
172
|
+
document.addEventListener('pointerdown', onDocPointer);
|
|
173
|
+
document.addEventListener('keydown', onKeyDown);
|
|
174
|
+
return () => {
|
|
175
|
+
btn.removeEventListener('click', onBtnClick);
|
|
176
|
+
copyBtn?.removeEventListener('click', onCopy);
|
|
177
|
+
document.removeEventListener('pointerdown', onDocPointer);
|
|
178
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
179
|
+
};
|
|
180
|
+
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { PresenterMode, type PresenterTone
|
|
1
|
+
import { PresenterMode, SessionState, type PresenterTone } from '@reticlehq/core';
|
|
2
2
|
import { type LogKind, type LogResult, type LogHandle } from './presenter-log.js';
|
|
3
|
-
import {
|
|
3
|
+
import { type PresenterOptions } from './presenter-config.js';
|
|
4
4
|
import { type PresenterRunState } from './presenter-run-state.js';
|
|
5
5
|
import { type ControlHandler } from './presenter-controls.js';
|
|
6
|
-
|
|
7
|
-
export { GlowPhase
|
|
8
|
-
export
|
|
6
|
+
import { Annotator } from '../review/annotator.js';
|
|
7
|
+
export { GlowPhase } from './presenter-config.js';
|
|
8
|
+
export type { PresenterOptions } from './presenter-config.js';
|
|
9
|
+
export { LOG_KIND, LOG_RESULT } from './presenter-log.js';
|
|
10
|
+
export type { LogHandle } from './presenter-log.js';
|
|
11
|
+
export type { ControlIntent, ControlHandler } from './presenter-controls.js';
|
|
9
12
|
export declare class Presenter {
|
|
10
13
|
#private;
|
|
11
14
|
constructor(options?: PresenterOptions);
|
|
@@ -30,6 +33,8 @@ export declare class Presenter {
|
|
|
30
33
|
get logMax(): number;
|
|
31
34
|
set logMax(n: number);
|
|
32
35
|
mount(): void;
|
|
36
|
+
/** Wire annotation chrome; expanding the HUD enters annotate mode. */
|
|
37
|
+
bindAnnotator(annotator: Annotator): void;
|
|
33
38
|
destroy(): void;
|
|
34
39
|
/**
|
|
35
40
|
* Session start: in 'session' border mode this fades the base border IN and keeps it on until
|
|
@@ -42,7 +47,7 @@ export declare class Presenter {
|
|
|
42
47
|
*/
|
|
43
48
|
sessionEnd(): void;
|
|
44
49
|
/**
|
|
45
|
-
* Record agent activity. Idempotent while busy
|
|
50
|
+
* Record agent activity. Idempotent while busy - only the first activity from idle/fading flips
|
|
46
51
|
* the glow on, so a burst never restarts the reticle-pulse animation (no strobe). Subsequent calls
|
|
47
52
|
* just refresh the last-activity timestamp and re-arm the idle check.
|
|
48
53
|
*/
|
|
@@ -50,7 +55,7 @@ export declare class Presenter {
|
|
|
50
55
|
/** Re-arm the quiet-window idle check (kept for reticle.ts's finally block). */
|
|
51
56
|
scheduleIdle(): void;
|
|
52
57
|
/** Test/diagnostic accessor for the current glow phase. */
|
|
53
|
-
glowPhase(): GlowPhase;
|
|
58
|
+
glowPhase(): import("./presenter-config.js").GlowPhase;
|
|
54
59
|
/** Current intent (reading vs acting), exposed for tests + the watcher. */
|
|
55
60
|
get mode(): PresenterMode;
|
|
56
61
|
/**
|
|
@@ -62,11 +67,11 @@ export declare class Presenter {
|
|
|
62
67
|
/** Agent-tunable idle-end window (reticle_session). Floored so it can't be set uselessly small. */
|
|
63
68
|
setIdleEndMs(ms: number): void;
|
|
64
69
|
/**
|
|
65
|
-
* The exported "run state" for the Copy/Export buttons
|
|
70
|
+
* The exported "run state" for the Copy/Export buttons - everything the page holds about this
|
|
66
71
|
* run: session id, url, duration, capability surface, per-kind counts, and the full activity log.
|
|
67
72
|
* (The full network/console ring-buffer lives server-side; this is the in-page run summary.)
|
|
68
73
|
*/
|
|
69
|
-
runState(): PresenterRunState
|
|
74
|
+
runState(): PresenterRunState | Record<string, unknown>;
|
|
70
75
|
/**
|
|
71
76
|
* Append an activity-log row. Accumulates (never overwrites): each call adds a timestamped row
|
|
72
77
|
* with a mode chip + text. Returns a handle to stamp the row's outcome glyph (✓/✗) later, or
|
|
@@ -77,7 +82,7 @@ export declare class Presenter {
|
|
|
77
82
|
narrate(text: string, level?: string): LogHandle | undefined;
|
|
78
83
|
/**
|
|
79
84
|
* Mirror the server's session.throttled state onto the HUD border. When throttled (tab
|
|
80
|
-
* backgrounded or stale), the border turns amber so the developer knows actions are no-oping
|
|
85
|
+
* backgrounded or stale), the border turns amber so the developer knows actions are no-oping -
|
|
81
86
|
* the same signal the agent already reads from result.session.throttled.
|
|
82
87
|
*/
|
|
83
88
|
setThrottled(throttled: boolean): void;
|