@reticlehq/browser 2.13.1 → 2.14.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/dist/actions/actions-dom.d.ts +0 -20
- package/dist/actions/actions-dom.js +0 -66
- package/dist/actions/actions-press.d.ts +10 -0
- package/dist/actions/actions-press.js +77 -0
- package/dist/actions/actions.d.ts +0 -89
- package/dist/actions/actions.js +24 -358
- package/dist/actions/appeared-text.d.ts +0 -20
- package/dist/actions/appeared-text.js +0 -36
- package/dist/actions/danger-context.d.ts +3 -0
- package/dist/actions/danger-context.js +39 -0
- package/dist/actions/scroll.d.ts +0 -9
- package/dist/actions/scroll.js +0 -7
- package/dist/actions/synthetic-input.d.ts +0 -7
- package/dist/actions/synthetic-input.js +0 -27
- package/dist/actions/value-input.d.ts +0 -30
- package/dist/actions/value-input.js +0 -33
- package/dist/commands/commands.d.ts +0 -2
- package/dist/commands/commands.js +0 -67
- package/dist/connect-options.d.ts +2 -96
- package/dist/dom/a11y.d.ts +0 -29
- package/dist/dom/a11y.js +1 -88
- package/dist/dom/auto-anchor.d.ts +0 -40
- package/dist/dom/auto-anchor.js +0 -33
- package/dist/dom/chart.d.ts +0 -61
- package/dist/dom/chart.js +0 -60
- package/dist/dom/desktop-capture.d.ts +0 -30
- package/dist/dom/desktop-capture.js +0 -72
- package/dist/dom/dom-ignore.d.ts +0 -30
- package/dist/dom/dom-ignore.js +0 -47
- package/dist/dom/occlusion.d.ts +0 -7
- package/dist/dom/occlusion.js +0 -7
- package/dist/dom/query.d.ts +0 -14
- package/dist/dom/query.js +48 -214
- package/dist/dom/realm.d.ts +0 -20
- package/dist/dom/realm.js +0 -28
- package/dist/dom/refs.d.ts +0 -76
- package/dist/dom/refs.js +2 -133
- package/dist/dom/shadow-registry.d.ts +0 -33
- package/dist/dom/shadow-registry.js +2 -72
- package/dist/dom/snapshot.d.ts +2 -43
- package/dist/dom/snapshot.js +26 -151
- package/dist/dom/source.d.ts +0 -44
- package/dist/dom/source.js +0 -45
- package/dist/dom/theme.d.ts +0 -37
- package/dist/dom/theme.js +2 -52
- package/dist/dom/virtualized.d.ts +0 -17
- package/dist/dom/virtualized.js +0 -27
- package/dist/edit-epoch.d.ts +0 -22
- package/dist/edit-epoch.js +0 -52
- package/dist/index.js +1 -23
- package/dist/observers/animation.d.ts +0 -1
- package/dist/observers/animation.js +0 -3
- package/dist/observers/blind-spots.d.ts +0 -26
- package/dist/observers/blind-spots.js +2 -61
- package/dist/observers/console.d.ts +1 -2
- package/dist/observers/console.js +41 -30
- package/dist/observers/context-open.d.ts +1 -11
- package/dist/observers/context-open.js +10 -14
- package/dist/observers/departure.d.ts +3 -0
- package/dist/observers/departure.js +52 -0
- package/dist/observers/dialogs.d.ts +2 -0
- package/dist/observers/dialogs.js +39 -0
- package/dist/observers/dom.js +0 -44
- package/dist/observers/download.d.ts +1 -2
- package/dist/observers/download.js +38 -55
- package/dist/observers/focus.d.ts +0 -6
- package/dist/observers/focus.js +0 -7
- package/dist/observers/frames.d.ts +0 -9
- package/dist/observers/frames.js +1 -28
- package/dist/observers/health.d.ts +0 -5
- package/dist/observers/health.js +1 -33
- package/dist/observers/install-all.d.ts +2 -0
- package/dist/observers/install-all.js +26 -27
- package/dist/observers/ipc.d.ts +0 -25
- package/dist/observers/ipc.js +0 -65
- package/dist/observers/navigation.d.ts +2 -0
- package/dist/observers/navigation.js +33 -0
- package/dist/observers/network-body.d.ts +5 -28
- package/dist/observers/network-body.js +11 -108
- package/dist/observers/network-redact.d.ts +1 -20
- package/dist/observers/network-redact.js +1 -80
- package/dist/observers/network-stream.d.ts +0 -21
- package/dist/observers/network-stream.js +1 -44
- package/dist/observers/network.d.ts +2 -26
- package/dist/observers/network.js +177 -294
- package/dist/observers/perf.d.ts +0 -10
- package/dist/observers/perf.js +0 -16
- package/dist/observers/route.d.ts +1 -2
- package/dist/observers/route.js +13 -19
- package/dist/observers/scroll.d.ts +0 -1
- package/dist/observers/scroll.js +0 -9
- package/dist/observers/sdk-failure.d.ts +1 -9
- package/dist/observers/sdk-failure.js +1 -30
- package/dist/observers/state.d.ts +1 -11
- package/dist/observers/state.js +13 -41
- package/dist/observers/storage.d.ts +0 -14
- package/dist/observers/storage.js +10 -34
- package/dist/observers/types.d.ts +0 -15
- package/dist/observers/types.js +0 -14
- package/dist/patching/capture-method.d.ts +0 -24
- package/dist/patching/capture-method.js +0 -26
- package/dist/presenter/overlay.d.ts +0 -1
- package/dist/presenter/overlay.js +0 -1
- package/dist/presenter/presenter-brand.d.ts +0 -19
- package/dist/presenter/presenter-brand.js +0 -21
- package/dist/presenter/presenter-config.d.ts +1 -105
- package/dist/presenter/presenter-config.js +2 -91
- package/dist/presenter/presenter-controls.d.ts +0 -29
- package/dist/presenter/presenter-controls.js +3 -131
- package/dist/presenter/presenter-dock-layout.d.ts +0 -3
- package/dist/presenter/presenter-dock-layout.js +0 -4
- package/dist/presenter/presenter-drag.d.ts +2 -24
- package/dist/presenter/presenter-drag.js +0 -26
- package/dist/presenter/presenter-effects.d.ts +0 -9
- package/dist/presenter/presenter-effects.js +0 -9
- package/dist/presenter/presenter-glow.d.ts +0 -21
- package/dist/presenter/presenter-glow.js +1 -27
- package/dist/presenter/presenter-heroicons-data.d.ts +0 -8
- package/dist/presenter/presenter-heroicons-data.js +0 -8
- package/dist/presenter/presenter-hud-chrome.d.ts +0 -10
- package/dist/presenter/presenter-hud-chrome.js +0 -10
- package/dist/presenter/presenter-icons.d.ts +0 -6
- package/dist/presenter/presenter-icons.js +0 -6
- package/dist/presenter/presenter-log.d.ts +0 -38
- package/dist/presenter/presenter-log.js +1 -45
- package/dist/presenter/presenter-report-copy.d.ts +5 -66
- package/dist/presenter/presenter-report-copy.js +5 -66
- package/dist/presenter/presenter-report-styles.d.ts +0 -6
- package/dist/presenter/presenter-report-styles.js +6 -6
- package/dist/presenter/presenter-report.d.ts +4 -7
- package/dist/presenter/presenter-report.js +18 -76
- package/dist/presenter/presenter-run-state.d.ts +0 -7
- package/dist/presenter/presenter-run-state.js +0 -5
- package/dist/presenter/presenter-settings-styles.d.ts +0 -1
- package/dist/presenter/presenter-settings-styles.js +0 -1
- package/dist/presenter/presenter-settings.d.ts +1 -23
- package/dist/presenter/presenter-settings.js +1 -31
- package/dist/presenter/presenter-shell-styles.js +2 -5
- package/dist/presenter/presenter-shell.d.ts +2 -18
- package/dist/presenter/presenter-shell.js +1 -73
- package/dist/presenter/presenter-styles.d.ts +0 -9
- package/dist/presenter/presenter-styles.js +0 -9
- package/dist/presenter/presenter-tally.d.ts +0 -5
- package/dist/presenter/presenter-tally.js +0 -4
- package/dist/presenter/presenter-test-helpers.d.ts +0 -2
- package/dist/presenter/presenter-test-helpers.js +0 -2
- package/dist/presenter/presenter-verbs.js +0 -7
- package/dist/presenter/presenter-workspace.d.ts +0 -4
- package/dist/presenter/presenter-workspace.js +1 -8
- package/dist/presenter/presenter.d.ts +0 -60
- package/dist/presenter/presenter.js +4 -118
- package/dist/recorder/recorder-styles.d.ts +0 -6
- package/dist/recorder/recorder-styles.js +0 -6
- package/dist/recorder/recorder.d.ts +0 -34
- package/dist/recorder/recorder.js +0 -49
- package/dist/registry/adapters.d.ts +0 -10
- package/dist/registry/adapters.js +0 -10
- package/dist/registry/auto-testids.d.ts +0 -19
- package/dist/registry/auto-testids.js +1 -21
- package/dist/registry/capabilities.d.ts +0 -31
- package/dist/registry/capabilities.js +1 -46
- package/dist/registry/commit-and-signal.d.ts +0 -6
- package/dist/registry/commit-and-signal.js +1 -7
- package/dist/registry/domains.d.ts +0 -8
- package/dist/registry/domains.js +0 -7
- package/dist/registry/emitter.d.ts +0 -14
- package/dist/registry/emitter.js +0 -10
- package/dist/registry/store-adapters.d.ts +0 -186
- package/dist/registry/store-adapters.js +0 -163
- package/dist/registry/stores.d.ts +0 -33
- package/dist/registry/stores.js +0 -59
- package/dist/reticle-presenter-helpers.d.ts +0 -13
- package/dist/reticle-presenter-helpers.js +0 -14
- package/dist/reticle.d.ts +1 -52
- package/dist/reticle.js +20 -145
- package/dist/review/annotator-styles.js +0 -7
- package/dist/review/annotator.d.ts +2 -13
- package/dist/review/annotator.js +0 -40
- package/dist/review/mark-anchor.d.ts +0 -11
- package/dist/review/mark-anchor.js +0 -8
- package/dist/security/serialization.d.ts +0 -20
- package/dist/security/serialization.js +1 -66
- package/dist/session-continuity.d.ts +0 -16
- package/dist/session-continuity.js +1 -20
- package/dist/timers/clock.d.ts +1 -14
- package/dist/timers/clock.js +59 -60
- package/dist/timers/native-console.js +0 -4
- package/dist/timers/native-timers.d.ts +0 -25
- package/dist/timers/native-timers.js +3 -33
- package/dist/transport/transport.d.ts +0 -51
- package/dist/transport/transport.js +3 -129
- package/dist/transport/unreachable-message.d.ts +0 -17
- package/dist/transport/unreachable-message.js +0 -17
- package/dist/util/captured-method.d.ts +0 -35
- package/dist/util/captured-method.js +0 -35
- package/package.json +2 -2
|
@@ -1,49 +1,15 @@
|
|
|
1
1
|
import { ImpactSnapshotSchema } from '@reticlehq/core';
|
|
2
|
-
/**
|
|
3
|
-
* What the report SAYS, kept away from how it looks.
|
|
4
|
-
*
|
|
5
|
-
* The wording here is the product's only claim about its own worth, so it is written once, in one
|
|
6
|
-
* place, and tested. Two audiences, two registers:
|
|
7
|
-
*
|
|
8
|
-
* - The REPORT is private. It is the user's own data, so it can carry everything, estimates
|
|
9
|
-
* included, as long as each estimate shows what it is measured against.
|
|
10
|
-
* - The SHARE card is public, and the research on developer stat-cards is blunt about what happens
|
|
11
|
-
* to a public card that leads with vendor savings: estimated token/time savings are the most
|
|
12
|
-
* mocked class of number in AI tooling (JetBrains measured ~10% against a viral 65% claim), and
|
|
13
|
-
* percentiles without a denominator get called misleading. So the card leads with what the
|
|
14
|
-
* user's own setup CAUGHT, and publishes its unknowns - the credibility move, and the thing a
|
|
15
|
-
* scoreboard would never do.
|
|
16
|
-
*/
|
|
17
|
-
/** Reticle's own links, as they appear in the report footer. */
|
|
18
2
|
export const REPORT_LINKS = {
|
|
19
3
|
DOCS: 'https://docs.reticle.sh',
|
|
20
4
|
SITE: 'https://reticle.sh',
|
|
21
5
|
GITHUB: 'https://github.com/reticlehq/reticle',
|
|
22
6
|
DISCORD: 'https://discord.gg/BwAbzv9ZRz',
|
|
23
7
|
};
|
|
24
|
-
/**
|
|
25
|
-
* The X handle used for `via=` on a share.
|
|
26
|
-
*
|
|
27
|
-
* Empty until somebody who owns the account fills it in, and the share URL omits the parameter
|
|
28
|
-
* while it is - a guessed handle credits a stranger, and there is no way for code to know.
|
|
29
|
-
*/
|
|
30
8
|
export const SHARE_VIA_HANDLE = '';
|
|
31
9
|
export const REPORT_TEXT = {
|
|
32
10
|
TITLE: 'Impact',
|
|
33
11
|
PROJECT: 'This project',
|
|
34
12
|
GLOBAL: 'Everything on this machine',
|
|
35
|
-
/**
|
|
36
|
-
* What `counts.failed` actually is: a verdict whose declared consequence did not hold.
|
|
37
|
-
*
|
|
38
|
-
* It used to read "defects caught before you saw them", which overclaims in the one direction a
|
|
39
|
-
* verification tool must never overclaim. A failed verdict is not proof of a defect in the app —
|
|
40
|
-
* it is equally the shape of an assertion that was wrong. Measured in the field: an agent
|
|
41
|
-
* asserted a clean console on an app with ordinary dev-mode logging, the verdict went red, and
|
|
42
|
-
* the panel reported a defect nobody had found.
|
|
43
|
-
*
|
|
44
|
-
* The honest word is what Reticle DID: it refused to pass them. That is true of the assertion
|
|
45
|
-
* error and the real bug alike, and it still reads as the tool having done its job.
|
|
46
|
-
*/
|
|
47
13
|
HERO_DEFECTS: 'checks Reticle refused to pass',
|
|
48
14
|
VERDICTS: 'Verdicts',
|
|
49
15
|
PASSED: 'passed',
|
|
@@ -61,21 +27,14 @@ export const REPORT_TEXT = {
|
|
|
61
27
|
ESTIMATE_TAG: 'estimate',
|
|
62
28
|
CHART: 'Verdicts, last 30 days',
|
|
63
29
|
DEFECTS: 'What broke',
|
|
64
|
-
DEFECTS_MORE: 'Manage all of them on the dashboard',
|
|
65
|
-
|
|
66
|
-
* What an UNLINKED user is told, and the only place the product tells them.
|
|
67
|
-
*
|
|
68
|
-
* The dashboard link renders only when `dashboardUrl` exists, which means only once a repo is
|
|
69
|
-
* already linked — so the person most likely to want one, watching this record climb on their own
|
|
70
|
-
* machine, was never told it existed. The single mention anywhere else is a daemon log line.
|
|
71
|
-
*
|
|
72
|
-
* Stated as a FACT about where the record lives, not as a pitch. It sits at the foot of a panel
|
|
73
|
-
* somebody opened on purpose, so it informs rather than interrupts, and it appears only once
|
|
74
|
-
* there is a verdict worth keeping — an offer to preserve nothing is just an advert.
|
|
75
|
-
*/
|
|
30
|
+
DEFECTS_MORE: 'Manage all of them on the dashboard — triage, assign, and push to GitHub',
|
|
31
|
+
DEFECT_LINK_TITLE: 'Open on the dashboard to triage or push to GitHub',
|
|
76
32
|
LOCAL_ONLY: 'This record stops at this machine.',
|
|
77
33
|
LOCAL_ONLY_ACTION: 'reticle login',
|
|
78
34
|
LOCAL_ONLY_TAIL: 'keeps it, and lets a team see it.',
|
|
35
|
+
UNLINKED: 'Signed in, but this repo is not linked.',
|
|
36
|
+
UNLINKED_ACTION: 'reticle link',
|
|
37
|
+
UNLINKED_TAIL: 'sends this record to your workspace.',
|
|
79
38
|
DEFECTS_NONE: 'Nothing has failed a declared consequence yet.',
|
|
80
39
|
EMPTY: 'Nothing recorded yet. Drive the app once and this fills in.',
|
|
81
40
|
SHARE: 'Share',
|
|
@@ -83,7 +42,6 @@ export const REPORT_TEXT = {
|
|
|
83
42
|
COPIED: 'Copied',
|
|
84
43
|
REFER: 'Send to a friend',
|
|
85
44
|
};
|
|
86
|
-
/** "4.2k", "1.3M" - a number a person reads at a glance rather than counts digits in. */
|
|
87
45
|
export function compactNumber(n) {
|
|
88
46
|
if (n < 1000)
|
|
89
47
|
return String(Math.round(n));
|
|
@@ -94,7 +52,6 @@ export function compactNumber(n) {
|
|
|
94
52
|
function trim(n) {
|
|
95
53
|
return n >= 10 ? String(Math.round(n)) : String(Math.round(n * 10) / 10);
|
|
96
54
|
}
|
|
97
|
-
/** "2h 14m", "47m", "38s" - the same duration vocabulary the activity strip uses. */
|
|
98
55
|
export function compactDuration(ms) {
|
|
99
56
|
const s = Math.floor(ms / 1000);
|
|
100
57
|
if (s < 60)
|
|
@@ -105,13 +62,6 @@ export function compactDuration(ms) {
|
|
|
105
62
|
const h = Math.floor(m / 60);
|
|
106
63
|
return 0 === m % 60 ? `${String(h)}h` : `${String(h)}h ${String(m % 60)}m`;
|
|
107
64
|
}
|
|
108
|
-
/**
|
|
109
|
-
* The post itself.
|
|
110
|
-
*
|
|
111
|
-
* Leads with defects caught, then the verdict split INCLUDING unknowns, then the superlative. No
|
|
112
|
-
* estimated savings, no percentile, no leaderboard: those are the four things the evidence says get
|
|
113
|
-
* a dev-tool card mocked rather than shared.
|
|
114
|
-
*/
|
|
115
65
|
export function buildShareText(scope, projectName) {
|
|
116
66
|
const c = scope.counts;
|
|
117
67
|
const where = projectName !== undefined && projectName.length > 0 ? ` on ${projectName}` : '';
|
|
@@ -127,29 +77,18 @@ export function buildShareText(scope, projectName) {
|
|
|
127
77
|
}
|
|
128
78
|
return lines.join('\n');
|
|
129
79
|
}
|
|
130
|
-
/** X share intent. `via` is omitted while no handle is configured. */
|
|
131
80
|
export function buildXShareUrl(text) {
|
|
132
81
|
const params = new URLSearchParams({ text, url: REPORT_LINKS.SITE });
|
|
133
82
|
if (SHARE_VIA_HANDLE.length > 0)
|
|
134
83
|
params.set('via', SHARE_VIA_HANDLE);
|
|
135
84
|
return `https://twitter.com/intent/tweet?${params.toString()}`;
|
|
136
85
|
}
|
|
137
|
-
/**
|
|
138
|
-
* LinkedIn share.
|
|
139
|
-
*
|
|
140
|
-
* `share-offsite` takes a url and NOTHING else - the title/summary parameters were deprecated in
|
|
141
|
-
* 2018 and are ignored, so the caption has to reach the composer some other way. The report copies
|
|
142
|
-
* it to the clipboard before opening this, which is the only path that works without asking the
|
|
143
|
-
* user for posting permissions.
|
|
144
|
-
*/
|
|
145
86
|
export function buildLinkedInShareUrl() {
|
|
146
87
|
return `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(REPORT_LINKS.SITE)}`;
|
|
147
88
|
}
|
|
148
|
-
/** What a referral says: the tool, not the sender's numbers. */
|
|
149
89
|
export function buildReferralText() {
|
|
150
90
|
return `I have been verifying my agent's work from inside the running app with Reticle - it returns pass/fail with the file:line to fix. ${REPORT_LINKS.SITE}`;
|
|
151
91
|
}
|
|
152
|
-
/** Narrow an unknown push payload to a snapshot. Invalid shapes are ignored, never rendered. */
|
|
153
92
|
export function parseImpactSnapshot(value) {
|
|
154
93
|
const parsed = ImpactSnapshotSchema.safeParse(value);
|
|
155
94
|
return parsed.success ? parsed.data : undefined;
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The impact report's surface.
|
|
3
|
-
*
|
|
4
|
-
* Same glass as the chat panel and anchored in the same slot above the toolbar, because it is the
|
|
5
|
-
* same object seen a different way: what this session is doing, and what every session has done.
|
|
6
|
-
*/
|
|
7
1
|
export declare const REPORT_CSS: string;
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { HUD_DROP_SHADOW } from './presenter-hud-chrome.js';
|
|
2
2
|
import { DOCK_ALIGN_ATTR, DOCK_ATTR, REPORT_ATTR, REPORT_PANEL_ATTR } from './presenter-config.js';
|
|
3
3
|
const OVERLAY = 'data-reticle-overlay';
|
|
4
|
-
/**
|
|
5
|
-
* The impact report's surface.
|
|
6
|
-
*
|
|
7
|
-
* Same glass as the chat panel and anchored in the same slot above the toolbar, because it is the
|
|
8
|
-
* same object seen a different way: what this session is doing, and what every session has done.
|
|
9
|
-
*/
|
|
10
4
|
export const REPORT_CSS = `
|
|
11
5
|
[${REPORT_PANEL_ATTR}]{
|
|
12
6
|
position:absolute;right:0;left:auto;bottom:calc(100% + 12px);z-index:31;
|
|
@@ -88,6 +82,12 @@ export const REPORT_CSS = `
|
|
|
88
82
|
[${REPORT_PANEL_ATTR}] .reticle-report-defect-source{
|
|
89
83
|
color:var(--reticle-faint);font-size:9.5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
|
|
90
84
|
overflow-wrap:anywhere;}
|
|
85
|
+
.reticle-report-defect-link{flex:none;display:inline-flex;align-items:center;justify-content:center;
|
|
86
|
+
width:20px;height:20px;border-radius:6px;color:var(--reticle-faint);pointer-events:auto;
|
|
87
|
+
opacity:0;transition:opacity .12s ease,color .12s ease,background .12s ease;}
|
|
88
|
+
.reticle-report-defect:hover .reticle-report-defect-link,
|
|
89
|
+
.reticle-report-defect-link:focus-visible{opacity:1;}
|
|
90
|
+
.reticle-report-defect-link:hover{color:var(--reticle-fg);background:rgba(255,255,255,.07);}
|
|
91
91
|
[${REPORT_PANEL_ATTR}] .reticle-report-defects-more{
|
|
92
92
|
display:inline-block;margin-top:8px;font-size:10px;color:var(--reticle-c-active);
|
|
93
93
|
text-decoration:none;}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import { type ImpactScope, type ImpactSnapshot } from '@reticlehq/core';
|
|
1
|
+
import { type AccountState, type ImpactScope, type ImpactSnapshot } from '@reticlehq/core';
|
|
2
2
|
export declare function reportPanelHtml(): string;
|
|
3
|
-
export declare function reportBodyHtml(scope: ImpactScope, dashboardUrl?: string): string;
|
|
4
|
-
|
|
5
|
-
/** Opened from the toolbar and from the chat, so the shell decides what else must close. */
|
|
3
|
+
export declare function reportBodyHtml(scope: ImpactScope, dashboardUrl?: string, account?: AccountState): string;
|
|
4
|
+
interface ReportHost {
|
|
6
5
|
onBeforeOpen?: () => void;
|
|
7
6
|
}
|
|
8
|
-
/** The report panel controller: scope toggle, live repaint, share + referral actions. */
|
|
9
7
|
export declare class PresenterReport {
|
|
10
8
|
#private;
|
|
11
9
|
constructor(host?: ReportHost);
|
|
12
10
|
mount(root: HTMLElement): void;
|
|
13
|
-
/** The record arrived from the daemon. Repaint only if the panel is on screen. */
|
|
14
11
|
setSnapshot(snapshot: ImpactSnapshot): void;
|
|
15
12
|
snapshot(): ImpactSnapshot | undefined;
|
|
16
13
|
isOpen(): boolean;
|
|
@@ -18,6 +15,6 @@ export declare class PresenterReport {
|
|
|
18
15
|
close(): void;
|
|
19
16
|
toggle(): void;
|
|
20
17
|
contains(node: Node): boolean;
|
|
21
|
-
/** The post text for whichever scope is showing. */
|
|
22
18
|
shareText(): string;
|
|
23
19
|
}
|
|
20
|
+
export {};
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import { IMPACT_DEFECT_LIMIT } from '@reticlehq/core';
|
|
1
|
+
import { IMPACT_DEFECT_LIMIT, } from '@reticlehq/core';
|
|
2
2
|
import { PresenterIcon, PRESENTER_ICON_SIZE, hiIconHtml } from './presenter-icons.js';
|
|
3
3
|
import { HUD_SURFACE_CLASS } from './presenter-hud-chrome.js';
|
|
4
4
|
import { REPORT_PANEL_ATTR, REPORT_ATTR, REPORT_CLOSE_ATTR } from './presenter-config.js';
|
|
5
5
|
import { REPORT_LINKS, REPORT_TEXT, buildLinkedInShareUrl, buildReferralText, buildShareText, buildXShareUrl, compactDuration, compactNumber, } from './presenter-report-copy.js';
|
|
6
|
-
/**
|
|
7
|
-
* The impact report: what Reticle has actually done for this user.
|
|
8
|
-
*
|
|
9
|
-
* Reads the local record only - the panel is a view over `.reticle/impact.json`, pushed by the
|
|
10
|
-
* daemon, never fetched from us. Two scopes (this project, this machine) behind one toggle.
|
|
11
|
-
*/
|
|
12
6
|
const SCOPE_ATTR = 'data-reticle-report-scope';
|
|
13
7
|
const SHARE_X_ATTR = 'data-reticle-share-x';
|
|
14
8
|
const SHARE_IN_ATTR = 'data-reticle-share-in';
|
|
@@ -17,7 +11,7 @@ const REFER_ATTR = 'data-reticle-refer';
|
|
|
17
11
|
const COPIED_FLASH_MS = 1600;
|
|
18
12
|
export function reportPanelHtml() {
|
|
19
13
|
const close = hiIconHtml(PresenterIcon.REMOVE, PRESENTER_ICON_SIZE.MIN);
|
|
20
|
-
return `<div ${REPORT_PANEL_ATTR} class="reticle-report ${HUD_SURFACE_CLASS}" role="
|
|
14
|
+
return `<div ${REPORT_PANEL_ATTR} class="reticle-report ${HUD_SURFACE_CLASS}" role="region" aria-label="Reticle impact" aria-hidden="true">
|
|
21
15
|
<div class="reticle-report-inner">
|
|
22
16
|
<div class="reticle-report-head">
|
|
23
17
|
<span class="reticle-report-title">${REPORT_TEXT.TITLE}</span>
|
|
@@ -40,19 +34,12 @@ export function reportPanelHtml() {
|
|
|
40
34
|
</div>
|
|
41
35
|
</div>`;
|
|
42
36
|
}
|
|
43
|
-
/** A stat card: the number, what it is, and - for an estimate - what it is measured against. */
|
|
44
37
|
function card(value, label, basis) {
|
|
45
38
|
const tag = basis === undefined
|
|
46
39
|
? ''
|
|
47
40
|
: `<span class="reticle-report-basis" title="${basis}">${REPORT_TEXT.ESTIMATE_TAG}</span>`;
|
|
48
41
|
return `<div class="reticle-report-card"><span class="reticle-report-value">${value}</span><span class="reticle-report-label">${label}${tag}</span></div>`;
|
|
49
42
|
}
|
|
50
|
-
/**
|
|
51
|
-
* A 30-day bar chart of verdicts, as inline spans.
|
|
52
|
-
*
|
|
53
|
-
* Bars rather than a line: a day with no verdicts is a real fact about the week, and a line chart
|
|
54
|
-
* interpolates straight through it.
|
|
55
|
-
*/
|
|
56
43
|
function chart(scope) {
|
|
57
44
|
const days = scope.days.slice(-30);
|
|
58
45
|
if (0 === days.length)
|
|
@@ -68,14 +55,6 @@ function chart(scope) {
|
|
|
68
55
|
.join('');
|
|
69
56
|
return `<div class="reticle-report-chart-wrap"><span class="reticle-report-section">${REPORT_TEXT.CHART}</span><div class="reticle-report-chart">${bars}</div></div>`;
|
|
70
57
|
}
|
|
71
|
-
/**
|
|
72
|
-
* Escape text that came from the app under test.
|
|
73
|
-
*
|
|
74
|
-
* A defect title is an element's accessible name or a verdict's failure reason — both of which are
|
|
75
|
-
* ultimately the CONTENT of somebody else's page, and this panel builds its DOM from an HTML string.
|
|
76
|
-
* Everything else the report renders is a number or a date; this is the first app-derived text to
|
|
77
|
-
* reach it, so the escaping arrives with it.
|
|
78
|
-
*/
|
|
79
58
|
function esc(value) {
|
|
80
59
|
return value
|
|
81
60
|
.replace(/&/g, '&')
|
|
@@ -83,46 +62,23 @@ function esc(value) {
|
|
|
83
62
|
.replace(/>/g, '>')
|
|
84
63
|
.replace(/"/g, '"');
|
|
85
64
|
}
|
|
86
|
-
/**
|
|
87
|
-
* The short list of what is currently broken.
|
|
88
|
-
*
|
|
89
|
-
* The hero number already says HOW MANY defects Reticle caught; this says WHICH ONES, which is the
|
|
90
|
-
* difference between a statistic and something a person can act on. Deliberately short: a panel in
|
|
91
|
-
* the corner of somebody's app is not a triage queue, and the link at the bottom is where the queue
|
|
92
|
-
* lives. When the project is not linked to a workspace there is no link and no nagging — the free
|
|
93
|
-
* tool is complete on its own.
|
|
94
|
-
*/
|
|
95
|
-
/**
|
|
96
|
-
* Whether a dashboard link is safe to render as a clickable href.
|
|
97
|
-
*
|
|
98
|
-
* The url arrives from `.reticle/cloud.json` — a file in somebody's repository, which means it is
|
|
99
|
-
* INPUT. Escaping the quotes stops it breaking out of the attribute but does nothing about the
|
|
100
|
-
* SCHEME, so `javascript:...` produced a link that ran code inside the developer's own application,
|
|
101
|
-
* from a panel Reticle injected there. Only the two schemes a dashboard can actually live on are
|
|
102
|
-
* allowed; anything else renders no link at all, which is the same state as an unlinked project and
|
|
103
|
-
* therefore already a supported one.
|
|
104
|
-
*/
|
|
105
65
|
function isSafeDashboardUrl(raw) {
|
|
106
66
|
try {
|
|
107
67
|
const scheme = new URL(raw).protocol;
|
|
108
68
|
return 'https:' === scheme || 'http:' === scheme;
|
|
109
69
|
}
|
|
110
70
|
catch {
|
|
111
|
-
// Not a url at all. A relative path cannot address a dashboard on another origin, so there is
|
|
112
|
-
// nothing to render and nothing lost by refusing it.
|
|
113
71
|
return false;
|
|
114
72
|
}
|
|
115
73
|
}
|
|
116
74
|
function defects(scope, dashboardUrl) {
|
|
117
|
-
/*
|
|
118
|
-
* Defaulted here as well as in the schema. Zod's default applies when a record is PARSED, and the
|
|
119
|
-
* snapshot reaching this panel is pushed straight from the daemon rather than round-tripped
|
|
120
|
-
* through the schema — so a record written by an older build arrives with no `defects` field at
|
|
121
|
-
* all and used to throw, taking the whole report down with it.
|
|
122
|
-
*/
|
|
123
75
|
const list = (scope.defects ?? []).slice(0, IMPACT_DEFECT_LIMIT);
|
|
124
76
|
if (0 === list.length)
|
|
125
77
|
return '';
|
|
78
|
+
const linked = dashboardUrl !== undefined && isSafeDashboardUrl(dashboardUrl);
|
|
79
|
+
const rowLink = linked
|
|
80
|
+
? `<a class="reticle-report-defect-link" href="${esc(dashboardUrl)}" target="_blank" rel="noreferrer noopener" title="${REPORT_TEXT.DEFECT_LINK_TITLE}" aria-label="${REPORT_TEXT.DEFECT_LINK_TITLE}">${hiIconHtml(PresenterIcon.VIEW, PRESENTER_ICON_SIZE.SEND)}</a>`
|
|
81
|
+
: '';
|
|
126
82
|
const rows = list
|
|
127
83
|
.map((d) => {
|
|
128
84
|
const detail = d.detail === undefined
|
|
@@ -131,17 +87,15 @@ function defects(scope, dashboardUrl) {
|
|
|
131
87
|
const source = d.source === undefined
|
|
132
88
|
? ''
|
|
133
89
|
: `<span class="reticle-report-defect-source">${esc(d.source)}</span>`;
|
|
134
|
-
return `<li class="reticle-report-defect"><span class="reticle-report-defect-title">${esc(d.title)}</span>${detail}${source}</li>`;
|
|
90
|
+
return `<li class="reticle-report-defect"><span class="reticle-report-defect-title">${esc(d.title)}</span>${detail}${source}${rowLink}</li>`;
|
|
135
91
|
})
|
|
136
92
|
.join('');
|
|
137
|
-
|
|
138
|
-
// this list is the recent tail of it.
|
|
139
|
-
const more = dashboardUrl === undefined || !isSafeDashboardUrl(dashboardUrl)
|
|
93
|
+
const more = !linked
|
|
140
94
|
? ''
|
|
141
95
|
: `<a class="reticle-report-defects-more" href="${esc(dashboardUrl)}" target="_blank" rel="noreferrer noopener">${REPORT_TEXT.DEFECTS_MORE}${scope.counts.failed > list.length ? ` (${String(scope.counts.failed)})` : ''}</a>`;
|
|
142
96
|
return `<div class="reticle-report-defects-wrap"><span class="reticle-report-section">${REPORT_TEXT.DEFECTS}</span><ul class="reticle-report-defects">${rows}</ul>${more}</div>`;
|
|
143
97
|
}
|
|
144
|
-
export function reportBodyHtml(scope, dashboardUrl) {
|
|
98
|
+
export function reportBodyHtml(scope, dashboardUrl, account) {
|
|
145
99
|
const c = scope.counts;
|
|
146
100
|
if (0 === c.calls)
|
|
147
101
|
return `<p class="reticle-report-empty">${REPORT_TEXT.EMPTY}</p>`;
|
|
@@ -164,27 +118,20 @@ export function reportBodyHtml(scope, dashboardUrl) {
|
|
|
164
118
|
card(compactNumber(scope.savings.tokens.value), REPORT_TEXT.SAVED_TOKENS, scope.savings.tokens.basis),
|
|
165
119
|
card(compactDuration(scope.savings.minutes.value * 60_000), REPORT_TEXT.SAVED_MINUTES, scope.savings.minutes.basis),
|
|
166
120
|
].join('');
|
|
167
|
-
return `${streak}${hero}${verdicts}<div class="reticle-report-grid">${cards}</div>${defects(scope, dashboardUrl)}${chart(scope)}${localOnly(scope, dashboardUrl)}`;
|
|
121
|
+
return `${streak}${hero}${verdicts}<div class="reticle-report-grid">${cards}</div>${defects(scope, dashboardUrl)}${chart(scope)}${localOnly(scope, dashboardUrl, account)}`;
|
|
168
122
|
}
|
|
169
|
-
|
|
170
|
-
* The one line an UNLINKED user is shown about the dashboard.
|
|
171
|
-
*
|
|
172
|
-
* Absent `dashboardUrl` IS the unlinked signal — it is only ever set from a repo's cloud.json — so
|
|
173
|
-
* this needs no new plumbing and cannot be wrong about the state it describes.
|
|
174
|
-
*
|
|
175
|
-
* Gated on a VERDICT, not on tool calls. Somebody who has driven the app but proved nothing has not
|
|
176
|
-
* yet received the thing this offers to preserve, and offering to keep nothing is an advert. Past
|
|
177
|
-
* that bar it is a fact about where their record lives, at the foot of a panel they opened on
|
|
178
|
-
* purpose — which is why it does not need to be dismissible.
|
|
179
|
-
*/
|
|
180
|
-
function localOnly(scope, dashboardUrl) {
|
|
123
|
+
function localOnly(scope, dashboardUrl, account) {
|
|
181
124
|
if (dashboardUrl !== undefined)
|
|
182
125
|
return '';
|
|
183
126
|
if (scope.counts.verdicts <= 0)
|
|
184
127
|
return '';
|
|
185
|
-
|
|
128
|
+
if (account === undefined)
|
|
129
|
+
return '';
|
|
130
|
+
const [lead, action, tail] = account.signedIn
|
|
131
|
+
? [REPORT_TEXT.UNLINKED, REPORT_TEXT.UNLINKED_ACTION, REPORT_TEXT.UNLINKED_TAIL]
|
|
132
|
+
: [REPORT_TEXT.LOCAL_ONLY, REPORT_TEXT.LOCAL_ONLY_ACTION, REPORT_TEXT.LOCAL_ONLY_TAIL];
|
|
133
|
+
return `<p class="reticle-report-local-only">${lead} <code>${action}</code> ${tail}</p>`;
|
|
186
134
|
}
|
|
187
|
-
/** The report panel controller: scope toggle, live repaint, share + referral actions. */
|
|
188
135
|
export class PresenterReport {
|
|
189
136
|
#panel;
|
|
190
137
|
#body;
|
|
@@ -217,8 +164,6 @@ export class PresenterReport {
|
|
|
217
164
|
});
|
|
218
165
|
root.querySelector(`[${SHARE_IN_ATTR}]`)?.addEventListener('click', (e) => {
|
|
219
166
|
e.stopPropagation();
|
|
220
|
-
// LinkedIn ignores every text parameter, so the caption goes to the clipboard first and the
|
|
221
|
-
// composer opens on the link - the only route that needs no posting permission.
|
|
222
167
|
void this.#copy(this.shareText());
|
|
223
168
|
this.#openShare(buildLinkedInShareUrl());
|
|
224
169
|
});
|
|
@@ -231,7 +176,6 @@ export class PresenterReport {
|
|
|
231
176
|
void this.#copy(buildReferralText(), e.currentTarget);
|
|
232
177
|
});
|
|
233
178
|
}
|
|
234
|
-
/** The record arrived from the daemon. Repaint only if the panel is on screen. */
|
|
235
179
|
setSnapshot(snapshot) {
|
|
236
180
|
this.#snapshot = snapshot;
|
|
237
181
|
if (this.isOpen())
|
|
@@ -264,7 +208,6 @@ export class PresenterReport {
|
|
|
264
208
|
contains(node) {
|
|
265
209
|
return true === this.#panel?.contains(node);
|
|
266
210
|
}
|
|
267
|
-
/** The post text for whichever scope is showing. */
|
|
268
211
|
shareText() {
|
|
269
212
|
const snap = this.#snapshot;
|
|
270
213
|
if (snap === undefined)
|
|
@@ -286,7 +229,7 @@ export class PresenterReport {
|
|
|
286
229
|
this.#body.innerHTML =
|
|
287
230
|
scope === undefined
|
|
288
231
|
? `<p class="reticle-report-empty">${REPORT_TEXT.EMPTY}</p>`
|
|
289
|
-
: reportBodyHtml(scope, this.#snapshot?.dashboardUrl);
|
|
232
|
+
: reportBodyHtml(scope, this.#snapshot?.dashboardUrl, this.#snapshot?.account);
|
|
290
233
|
}
|
|
291
234
|
#openShare(url) {
|
|
292
235
|
window.open(url, '_blank', 'noopener,noreferrer');
|
|
@@ -296,7 +239,6 @@ export class PresenterReport {
|
|
|
296
239
|
await navigator.clipboard?.writeText(text);
|
|
297
240
|
}
|
|
298
241
|
catch {
|
|
299
|
-
// A blocked clipboard is not worth an error dialog over; the text is on screen either way.
|
|
300
242
|
}
|
|
301
243
|
if (button instanceof HTMLElement) {
|
|
302
244
|
const original = button.textContent ?? '';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { SessionState } from '@reticlehq/core';
|
|
2
2
|
import { type LogKind, type LogResult } from './presenter-log.js';
|
|
3
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
4
|
export interface PresenterRunState {
|
|
6
5
|
session: string;
|
|
7
6
|
url: string;
|
|
@@ -24,7 +23,6 @@ export interface PresenterRunState {
|
|
|
24
23
|
result?: LogResult;
|
|
25
24
|
}[];
|
|
26
25
|
}
|
|
27
|
-
/** Everything the controller hands the builder - the live fields a run state is computed from. */
|
|
28
26
|
interface RunStateInput {
|
|
29
27
|
sessionId: string;
|
|
30
28
|
state: SessionState;
|
|
@@ -38,10 +36,5 @@ interface RunStateInput {
|
|
|
38
36
|
result?: LogResult;
|
|
39
37
|
}[];
|
|
40
38
|
}
|
|
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
39
|
export declare function buildRunState(input: RunStateInput): PresenterRunState;
|
|
47
40
|
export {};
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { SessionState } from '@reticlehq/core';
|
|
2
2
|
import { LOG_KIND, LOG_RESULT } from './presenter-log.js';
|
|
3
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
4
|
export function buildRunState(input) {
|
|
10
5
|
const start = input.startMs ?? input.now;
|
|
11
6
|
const counts = { reads: 0, acts: 0, narrations: 0, human: 0, passes: 0, fails: 0 };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { SETTINGS_PANEL_ATTR, SETTINGS_ATTR, DOCK_ATTR, DOCK_ALIGN_ATTR, SETTINGS_PLACEMENT_ATTR, } from './presenter-config.js';
|
|
2
2
|
import { HUD_DROP_SHADOW, HUD_SURFACE_CLASS, HUD_SURFACE_PAINT } from './presenter-hud-chrome.js';
|
|
3
|
-
/** Compact settings card - dock-anchored above the HUD pill. */
|
|
4
3
|
export const SETTINGS_CSS = `
|
|
5
4
|
[${'data-reticle-overlay'}][${SETTINGS_ATTR}="1"] [${'data-reticle-chat-panel'}]{
|
|
6
5
|
display:none !important;visibility:hidden !important;pointer-events:none !important;}
|
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
import { SETTINGS_CSS } from './presenter-settings-styles.js';
|
|
2
2
|
export { SETTINGS_CSS };
|
|
3
|
-
/** How much detail lands in copied/exported run state. */
|
|
4
3
|
export declare const OutputDetail: {
|
|
5
4
|
readonly MINIMAL: "minimal";
|
|
6
5
|
readonly STANDARD: "standard";
|
|
7
6
|
readonly VERBOSE: "verbose";
|
|
8
7
|
};
|
|
9
8
|
export type OutputDetail = (typeof OutputDetail)[keyof typeof OutputDetail];
|
|
10
|
-
/**
|
|
11
|
-
* Status themes: ONE choice, three colours.
|
|
12
|
-
*
|
|
13
|
-
* This was four separate pickers - a chrome accent plus a swatch row per state - which is 28
|
|
14
|
-
* decisions to land on a set that works together. A theme is a combination we have already checked
|
|
15
|
-
* reads as a progression (working -> waiting -> done) and against a dark app, so the choice is
|
|
16
|
-
* "which mood", not "which four hex values".
|
|
17
|
-
*/
|
|
18
9
|
export declare const StatusThemeId: {
|
|
19
10
|
readonly SIGNAL: "signal";
|
|
20
11
|
readonly TRAFFIC: "traffic";
|
|
@@ -23,7 +14,7 @@ export declare const StatusThemeId: {
|
|
|
23
14
|
readonly EMBER: "ember";
|
|
24
15
|
};
|
|
25
16
|
export type StatusThemeId = (typeof StatusThemeId)[keyof typeof StatusThemeId];
|
|
26
|
-
|
|
17
|
+
interface StatusTheme {
|
|
27
18
|
id: StatusThemeId;
|
|
28
19
|
label: string;
|
|
29
20
|
active: string;
|
|
@@ -34,13 +25,7 @@ export declare const STATUS_THEMES: readonly StatusTheme[];
|
|
|
34
25
|
export declare function statusTheme(id: StatusThemeId): StatusTheme;
|
|
35
26
|
export interface PresenterSettings {
|
|
36
27
|
outputDetail: OutputDetail;
|
|
37
|
-
/**
|
|
38
|
-
* The colours the HUD signals session state with - the dot, the panel wash, the page glow, the
|
|
39
|
-
* FAB halo and the annotation marks all read from whichever one is current. One choice, because
|
|
40
|
-
* the three have to work as a set and against the user's own app.
|
|
41
|
-
*/
|
|
42
28
|
statusThemeId: StatusThemeId;
|
|
43
|
-
/** The page-edge glow. Off leaves every other signal (dot, panel, FAB) in place. */
|
|
44
29
|
ambientGlow: boolean;
|
|
45
30
|
reactComponents: boolean;
|
|
46
31
|
hideUntilRestart: boolean;
|
|
@@ -53,21 +38,14 @@ export interface PresenterSettings {
|
|
|
53
38
|
}
|
|
54
39
|
export declare function getPresenterSettings(): PresenterSettings;
|
|
55
40
|
export declare function loadPresenterSettings(): PresenterSettings;
|
|
56
|
-
/** Settings panel markup - anchored above the gear in the toolbar. */
|
|
57
41
|
export declare function settingsPanelHtml(): string;
|
|
58
42
|
export interface SettingsHost {
|
|
59
43
|
onHideUntilRestart?: () => void;
|
|
60
44
|
onSettingsChange?: (settings: PresenterSettings) => void;
|
|
61
45
|
onBeforeOpen?: () => void;
|
|
62
46
|
}
|
|
63
|
-
/** Apply persisted settings onto the overlay + dock. */
|
|
64
47
|
export declare function applyPresenterSettings(root: HTMLElement, settings: PresenterSettings): void;
|
|
65
|
-
/**
|
|
66
|
-
* Toggle the full-page blocker. Only active while annotate mode is live AND the user opted in -
|
|
67
|
-
* never on a collapsed FAB, so real hover/click on the host app still works.
|
|
68
|
-
*/
|
|
69
48
|
export declare function syncPageBlocker(root: HTMLElement, settings: PresenterSettings, annotateLive: boolean): void;
|
|
70
|
-
/** Blocker node - sits under Reticle UI, above the host page. */
|
|
71
49
|
export declare function blockerHtml(): string;
|
|
72
50
|
export declare class PresenterSettingsPanel {
|
|
73
51
|
#private;
|
|
@@ -5,20 +5,11 @@ import { resetHudDockPosition } from './presenter-drag.js';
|
|
|
5
5
|
import { findDock, scheduleSyncDockLayout } from './presenter-dock-layout.js';
|
|
6
6
|
import { SETTINGS_CSS } from './presenter-settings-styles.js';
|
|
7
7
|
export { SETTINGS_CSS };
|
|
8
|
-
/** How much detail lands in copied/exported run state. */
|
|
9
8
|
export const OutputDetail = {
|
|
10
9
|
MINIMAL: 'minimal',
|
|
11
10
|
STANDARD: 'standard',
|
|
12
11
|
VERBOSE: 'verbose',
|
|
13
12
|
};
|
|
14
|
-
/**
|
|
15
|
-
* Status themes: ONE choice, three colours.
|
|
16
|
-
*
|
|
17
|
-
* This was four separate pickers - a chrome accent plus a swatch row per state - which is 28
|
|
18
|
-
* decisions to land on a set that works together. A theme is a combination we have already checked
|
|
19
|
-
* reads as a progression (working -> waiting -> done) and against a dark app, so the choice is
|
|
20
|
-
* "which mood", not "which four hex values".
|
|
21
|
-
*/
|
|
22
13
|
export const StatusThemeId = {
|
|
23
14
|
SIGNAL: 'signal',
|
|
24
15
|
TRAFFIC: 'traffic',
|
|
@@ -70,14 +61,6 @@ const DEFAULT_SETTINGS = {
|
|
|
70
61
|
blockPageInteractions: true,
|
|
71
62
|
showTally: false,
|
|
72
63
|
showTimestamps: true,
|
|
73
|
-
// ON by default: the chat IS the HUD's content, and shipping it off meant the default experience
|
|
74
|
-
// was a bare toolbar until somebody found the toggle. `expand()` has always opened the chat for
|
|
75
|
-
// the same reason; this is the other half — session start, with no click at all.
|
|
76
|
-
//
|
|
77
|
-
// Safe to default because `openChat()` expands a collapsed HUD, and session start is the one
|
|
78
|
-
// moment where that is what you want. A user who prefers the bare toolbar turns this off and it
|
|
79
|
-
// stays off: a stored `false` is honoured over the default, which is pinned in
|
|
80
|
-
// presenter-chat-default.test.ts so the product cannot change somebody's answer behind their back.
|
|
81
64
|
autoOpenChat: true,
|
|
82
65
|
reduceMotion: false,
|
|
83
66
|
};
|
|
@@ -101,10 +84,6 @@ export function loadPresenterSettings() {
|
|
|
101
84
|
? o['outputDetail']
|
|
102
85
|
: DEFAULT_SETTINGS.outputDetail,
|
|
103
86
|
reactComponents: true === o['reactComponents'],
|
|
104
|
-
// NOT read back from storage. "Until restart" has to mean until restart: persisted, it
|
|
105
|
-
// survived the reload that was supposed to undo it, and the only way back was clearing
|
|
106
|
-
// localStorage by hand - the HUD was simply gone, including the settings panel that turned
|
|
107
|
-
// it off. It is a this-page-only switch, so it lives only in memory.
|
|
108
87
|
hideUntilRestart: false,
|
|
109
88
|
statusThemeId: isStatusThemeId(o['statusThemeId'])
|
|
110
89
|
? o['statusThemeId']
|
|
@@ -140,7 +119,6 @@ function persistSettings(next) {
|
|
|
140
119
|
localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(next));
|
|
141
120
|
}
|
|
142
121
|
catch {
|
|
143
|
-
/* quota / private mode - settings still apply for this page */
|
|
144
122
|
}
|
|
145
123
|
}
|
|
146
124
|
function patchSettings(patch) {
|
|
@@ -168,7 +146,6 @@ function settingsCheckRow(key, label, checked) {
|
|
|
168
146
|
<span class="reticle-settings-check-label">${label}</span>
|
|
169
147
|
</label>`;
|
|
170
148
|
}
|
|
171
|
-
/** Settings panel markup - anchored above the gear in the toolbar. */
|
|
172
149
|
export function settingsPanelHtml() {
|
|
173
150
|
const close = hiIconHtml(PresenterIcon.REMOVE, PRESENTER_ICON_SIZE.MIN);
|
|
174
151
|
const caret = hiIconHtml(PresenterIcon.CARET_RIGHT, PRESENTER_ICON_SIZE.HELP);
|
|
@@ -180,7 +157,7 @@ export function settingsPanelHtml() {
|
|
|
180
157
|
const autoChatHelp = 'On by default. Opens the agent chat by itself when a session starts and when you expand the HUD. Off leaves the toolbar bare until you ask for the chat.';
|
|
181
158
|
const motionHelp = 'Reduce HUD animations for accessibility';
|
|
182
159
|
const glowHelp = 'Glow the page edges in the status colour while a session is live. Off keeps the HUD signals and leaves your app alone.';
|
|
183
|
-
return `<div ${SETTINGS_PANEL_ATTR} class="reticle-settings ${HUD_SURFACE_CLASS}" role="
|
|
160
|
+
return `<div ${SETTINGS_PANEL_ATTR} class="reticle-settings ${HUD_SURFACE_CLASS}" role="region" aria-label="Reticle settings" aria-hidden="true">
|
|
184
161
|
<div class="reticle-settings-inner">
|
|
185
162
|
<div class="reticle-settings-head">
|
|
186
163
|
<span class="reticle-settings-title">Settings</span>
|
|
@@ -213,7 +190,6 @@ export function settingsPanelHtml() {
|
|
|
213
190
|
</div>
|
|
214
191
|
</div>`;
|
|
215
192
|
}
|
|
216
|
-
/** Apply persisted settings onto the overlay + dock. */
|
|
217
193
|
export function applyPresenterSettings(root, settings) {
|
|
218
194
|
const theme = statusTheme(settings.statusThemeId);
|
|
219
195
|
root.style.setProperty('--reticle-mark-accent', theme.active);
|
|
@@ -235,14 +211,9 @@ export function applyPresenterSettings(root, settings) {
|
|
|
235
211
|
tally.setAttribute('hidden', '');
|
|
236
212
|
}
|
|
237
213
|
}
|
|
238
|
-
/**
|
|
239
|
-
* Toggle the full-page blocker. Only active while annotate mode is live AND the user opted in -
|
|
240
|
-
* never on a collapsed FAB, so real hover/click on the host app still works.
|
|
241
|
-
*/
|
|
242
214
|
export function syncPageBlocker(root, settings, annotateLive) {
|
|
243
215
|
root.setAttribute(BLOCK_ATTR, settings.blockPageInteractions && annotateLive ? '1' : '0');
|
|
244
216
|
}
|
|
245
|
-
/** Blocker node - sits under Reticle UI, above the host page. */
|
|
246
217
|
export function blockerHtml() {
|
|
247
218
|
return '<div data-reticle-blocker aria-hidden="true"></div>';
|
|
248
219
|
}
|
|
@@ -470,7 +441,6 @@ export class PresenterSettingsPanel {
|
|
|
470
441
|
el.textContent = on ? '✓' : '';
|
|
471
442
|
}
|
|
472
443
|
}
|
|
473
|
-
/** One row of themes: each chip shows the whole set - active, idle, ended - in order. */
|
|
474
444
|
#buildThemes() {
|
|
475
445
|
const host = this.#panel?.querySelector('[data-reticle-settings-themes]');
|
|
476
446
|
if (null === host || undefined === host)
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Floating HUD shell styles - FAB, morphing toolbar, and agent chat panel.
|
|
3
|
-
* Split from presenter-styles.ts so the controller stays under the size cap.
|
|
4
|
-
*/
|
|
5
1
|
import { LOG_TIME_ATTR } from './presenter-log.js';
|
|
2
|
+
import { Z_HUD_TOOLTIP } from './presenter-config.js';
|
|
6
3
|
import { CHAT_ATTR, CHAT_PILL_ATTR, CHAT_PLACEMENT_ATTR, DOCK_ALIGN_ATTR, DOCK_ATTR, LOG_TIMESTAMPS_ATTR, MIN_ATTR, REDUCE_MOTION_ATTR, LIVENESS_ATTR, } from './presenter-config.js';
|
|
7
4
|
import { HUD_DROP_SHADOW, HUD_SURFACE_FILL } from './presenter-hud-chrome.js';
|
|
8
5
|
const OVERLAY = 'data-reticle-overlay';
|
|
@@ -289,7 +286,7 @@ export const SHELL_CSS = `
|
|
|
289
286
|
[${HUD}] .reticle-tb-tip{
|
|
290
287
|
position:absolute;bottom:calc(100% + 14px);left:50%;transform:translateX(-50%) scale(.95);
|
|
291
288
|
padding:6px 10px;background:#1a1a1a;color:rgba(255,255,255,.9);font-size:12px;font-weight:500;
|
|
292
|
-
border-radius:8px;white-space:nowrap;opacity:0;visibility:hidden;pointer-events:none;z-index
|
|
289
|
+
border-radius:8px;white-space:nowrap;opacity:0;visibility:hidden;pointer-events:none;z-index:${String(Z_HUD_TOOLTIP)};
|
|
293
290
|
box-shadow:0 2px 8px rgba(0,0,0,.3);transition:opacity .135s ease,transform .135s ease,visibility .135s;}
|
|
294
291
|
[${HUD}] .reticle-tb-tip::after{
|
|
295
292
|
content:"";position:absolute;top:calc(100% - 4px);left:50%;transform:translateX(-50%) rotate(45deg);
|