@reticlehq/browser 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/actions-dom.js +44 -43
- package/dist/actions/actions-press.d.ts +10 -4
- package/dist/actions/actions-press.js +108 -17
- package/dist/actions/actions.d.ts +2 -0
- package/dist/actions/actions.js +25 -16
- package/dist/actions/danger-context.js +1 -1
- package/dist/connect-options.d.ts +1 -0
- package/dist/dom/a11y.js +13 -4
- package/dist/dom/addressing/refs.js +2 -1
- package/dist/dom/addressing/testid-attr.d.ts +4 -0
- package/dist/dom/addressing/testid-attr.js +14 -0
- package/dist/dom/query.d.ts +1 -0
- package/dist/dom/query.js +38 -11
- package/dist/dom/snapshot.js +1 -0
- package/dist/observers/departure.js +51 -9
- package/dist/observers/dom.js +3 -2
- package/dist/observers/field.js +5 -3
- package/dist/observers/health.js +63 -2
- package/dist/observers/network-stream.d.ts +1 -1
- package/dist/observers/network-stream.js +3 -3
- package/dist/observers/network.js +1 -1
- package/dist/observers/storage.js +6 -1
- package/dist/presenter/carousel/carousel.d.ts +5 -2
- package/dist/presenter/carousel/carousel.js +34 -7
- package/dist/presenter/carousel/offer-card.d.ts +2 -2
- package/dist/presenter/carousel/offer-card.js +2 -1
- package/dist/presenter/carousel/panel-slides.d.ts +4 -3
- package/dist/presenter/carousel/panel-slides.js +43 -6
- package/dist/presenter/carousel/talk-card.d.ts +1 -1
- package/dist/presenter/chrome/log-kinds.d.ts +5 -0
- package/dist/presenter/chrome/log-kinds.js +1 -0
- package/dist/presenter/chrome/log-memory.d.ts +12 -0
- package/dist/presenter/chrome/log-memory.js +39 -0
- package/dist/presenter/chrome/presenter-hud-chrome.d.ts +1 -0
- package/dist/presenter/chrome/presenter-hud-chrome.js +7 -1
- package/dist/presenter/chrome/presenter-log.d.ts +5 -4
- package/dist/presenter/chrome/presenter-log.js +55 -5
- package/dist/presenter/chrome/presenter-report-copy.d.ts +11 -1
- package/dist/presenter/chrome/presenter-report-copy.js +14 -1
- package/dist/presenter/hud-telemetry.js +31 -2
- package/dist/presenter/icons/presenter-heroicons-data.d.ts +1 -0
- package/dist/presenter/icons/presenter-heroicons-data.js +4 -3
- package/dist/presenter/icons/presenter-icons.d.ts +2 -0
- package/dist/presenter/icons/presenter-icons.js +2 -0
- package/dist/presenter/presenter-account.d.ts +5 -4
- package/dist/presenter/presenter-account.js +23 -10
- package/dist/presenter/presenter-chat-views.d.ts +21 -0
- package/dist/presenter/presenter-chat-views.js +382 -0
- package/dist/presenter/presenter-config.d.ts +3 -2
- package/dist/presenter/presenter-config.js +4 -3
- package/dist/presenter/presenter-controls.d.ts +4 -2
- package/dist/presenter/presenter-controls.js +231 -51
- package/dist/presenter/presenter-design-tokens.d.ts +1 -0
- package/dist/presenter/presenter-design-tokens.js +34 -0
- package/dist/presenter/presenter-dock-layout.js +1 -1
- package/dist/presenter/presenter-frame.d.ts +12 -0
- package/dist/presenter/presenter-frame.js +189 -0
- package/dist/presenter/presenter-plan.d.ts +10 -0
- package/dist/presenter/presenter-plan.js +185 -0
- package/dist/presenter/presenter-report-styles.js +7 -0
- package/dist/presenter/presenter-report.d.ts +1 -1
- package/dist/presenter/presenter-report.js +53 -16
- package/dist/presenter/presenter-settings-styles.js +10 -0
- package/dist/presenter/presenter-settings.d.ts +5 -0
- package/dist/presenter/presenter-settings.js +71 -11
- package/dist/presenter/presenter-shell-styles.js +39 -42
- package/dist/presenter/presenter-shell.d.ts +8 -1
- package/dist/presenter/presenter-shell.js +124 -72
- package/dist/presenter/presenter-styles.js +9 -1
- package/dist/presenter/presenter.d.ts +4 -3
- package/dist/presenter/presenter.js +101 -13
- package/dist/presenter/tour/tour.d.ts +4 -1
- package/dist/presenter/tour/tour.js +6 -4
- package/dist/recorder/recorder.js +2 -2
- package/dist/registry/auto-testids.js +3 -4
- package/dist/registry/declared-platform.js +2 -0
- package/dist/reticle-inject.js +880 -513
- package/dist/reticle.d.ts +10 -1
- package/dist/reticle.js +73 -9
- package/dist/review/annotator-styles.d.ts +1 -1
- package/dist/review/annotator.d.ts +7 -0
- package/dist/review/annotator.js +20 -2
- package/dist/review/mark-anchor.js +2 -2
- package/dist/session-continuity.js +2 -1
- package/dist/storage-keys.d.ts +14 -0
- package/dist/storage-keys.js +17 -0
- package/package.json +3 -2
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import { DEFAULT_PLATFORM_URL } from '@reticlehq/core';
|
|
2
|
+
import { marksForAgent } from '../review/marks-for-agent.js';
|
|
3
|
+
import { ANNOTATE_BTN_ATTR, CHAT_TOGGLE_ATTR, CLEAR_MARKS_ATTR, MARKERS_BTN_ATTR, } from './presenter-config.js';
|
|
4
|
+
import { hiIconHtml, hiToggleIconHtml, PRESENTER_ICON_SIZE, PresenterIcon, } from './icons/presenter-icons.js';
|
|
5
|
+
import { HUD_GLASS_PAINT } from './chrome/presenter-hud-chrome.js';
|
|
6
|
+
import { creditsLeft } from './presenter-settings.js';
|
|
7
|
+
import { esc, isSafeDashboardUrl } from './chrome/presenter-safe-html.js';
|
|
8
|
+
import { ReticleStorageKey } from '../storage-keys.js';
|
|
9
|
+
const HISTORY_KEY = ReticleStorageKey.ANNOTATION_HISTORY;
|
|
10
|
+
const HISTORY_LIMIT = 200;
|
|
11
|
+
const HARNESS_SETUP_PATH = '/settings?group=project#model';
|
|
12
|
+
const HARNESS_PLAN_PATH = '/settings?group=billing';
|
|
13
|
+
export function platformBase(config, account) {
|
|
14
|
+
const base = [config?.platformUrl, account.host].find((url) => url !== undefined && isSafeDashboardUrl(url));
|
|
15
|
+
return esc((base ?? DEFAULT_PLATFORM_URL).replace(/\/+$/, ''));
|
|
16
|
+
}
|
|
17
|
+
function isHistoricalAnnotation(item) {
|
|
18
|
+
if ('object' !== typeof item || null === item)
|
|
19
|
+
return false;
|
|
20
|
+
const value = item;
|
|
21
|
+
return ('string' === typeof value.id &&
|
|
22
|
+
'string' === typeof value.note &&
|
|
23
|
+
'string' === typeof value.label &&
|
|
24
|
+
'string' === typeof value.anchor &&
|
|
25
|
+
'string' === typeof value.route &&
|
|
26
|
+
'number' === typeof value.createdAt &&
|
|
27
|
+
'string' === typeof value.pageUrl);
|
|
28
|
+
}
|
|
29
|
+
function readHistory() {
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(localStorage.getItem(HISTORY_KEY) ?? '[]');
|
|
32
|
+
if (!Array.isArray(parsed))
|
|
33
|
+
return [];
|
|
34
|
+
return parsed.filter(isHistoricalAnnotation).slice(0, HISTORY_LIMIT);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function saveHistory(items) {
|
|
41
|
+
try {
|
|
42
|
+
localStorage.setItem(HISTORY_KEY, JSON.stringify(items.slice(0, HISTORY_LIMIT)));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export const CHAT_VIEWS_HTML = `
|
|
48
|
+
<div data-reticle-harness-spot class="reticle-harness-spot" hidden></div>`;
|
|
49
|
+
export const FLOWS_PAGE_HTML = `<section data-reticle-page-panel="flows" class="reticle-page-panel reticle-flows-view" role="region" aria-label="Saved Flows" hidden>
|
|
50
|
+
<div class="reticle-page-heading"><span class="reticle-page-titles"><strong>Saved flows</strong><span class="reticle-page-subtitle">Journeys your agent verified, replayable here</span></span><button type="button" data-reticle-page-close aria-label="Close Saved Flows" title="Close">×</button></div>
|
|
51
|
+
<div data-reticle-all-flows class="reticle-all-flows"></div>
|
|
52
|
+
</section>`;
|
|
53
|
+
const NAV_ICON_SIZE = PRESENTER_ICON_SIZE.NAV;
|
|
54
|
+
export const CHAT_VIEWS_NAV_HTML = `<nav class="reticle-chat-nav" aria-label="Reticle views">
|
|
55
|
+
<button type="button" ${CHAT_TOGGLE_ATTR} data-reticle-chat-view-btn="activity" aria-label="Agent log" title="Agent log" aria-current="page">${hiIconHtml(PresenterIcon.MESSAGE, NAV_ICON_SIZE)}</button>
|
|
56
|
+
<button type="button" data-reticle-chat-view-btn="flows" aria-label="Saved flows" title="Saved flows">${hiIconHtml(PresenterIcon.LAYOUT, NAV_ICON_SIZE)}</button>
|
|
57
|
+
<button type="button" data-reticle-chat-view-btn="annotations" aria-label="Notes" title="Notes">${hiIconHtml(PresenterIcon.NOTES, NAV_ICON_SIZE)}<span data-reticle-note-count class="reticle-nav-count" hidden></span></button>
|
|
58
|
+
<button type="button" data-reticle-chat-impact class="reticle-chat-impact" aria-label="Open Impact" title="Impact">${hiIconHtml(PresenterIcon.CHART, NAV_ICON_SIZE)}<span data-reticle-chat-verdicts class="reticle-nav-count"></span></button>
|
|
59
|
+
</nav>`;
|
|
60
|
+
const ANNOTATION_ACTION_ICON_SIZE = PRESENTER_ICON_SIZE.TOOLBAR;
|
|
61
|
+
const markersLabel = 'Show note markers on the page';
|
|
62
|
+
const clearLabel = 'Clear notes from this page';
|
|
63
|
+
const copyAllLabel = 'Copy all notes';
|
|
64
|
+
const NOTES_TEXT = {
|
|
65
|
+
PAGE_EMPTY: 'No notes on this page',
|
|
66
|
+
PAGE_HINT: 'Select Add notes, then click anything on the page to pin feedback for your agent.',
|
|
67
|
+
HISTORY_EMPTY: 'No saved notes yet',
|
|
68
|
+
HISTORY_HINT: 'Notes from every page you annotate are kept here.',
|
|
69
|
+
};
|
|
70
|
+
export const ANNOTATIONS_HTML = `<section data-reticle-page-panel="annotations" class="reticle-page-panel reticle-annotations-view" role="region" aria-label="Notes" hidden>
|
|
71
|
+
<div class="reticle-page-heading"><span class="reticle-page-titles"><strong>Notes</strong><span class="reticle-page-subtitle">Pin feedback on the page for your agent</span></span><button type="button" ${ANNOTATE_BTN_ATTR} class="reticle-add-notes reticle-primary-btn" title="Add notes" aria-label="Add notes" aria-pressed="false" data-active="0"><span class="reticle-add-notes-icon">${hiIconHtml(PresenterIcon.ANNOTATE, PRESENTER_ICON_SIZE.TOOLBAR)}</span><span data-reticle-notes-toggle-label>Add notes</span></button><button type="button" data-reticle-page-close aria-label="Close Notes" title="Close">×</button></div>
|
|
72
|
+
<div class="reticle-annotations-tabs" role="group" aria-label="Notes lists">
|
|
73
|
+
<span class="reticle-segmented"><button type="button" data-reticle-annotation-tab="current" aria-pressed="true">This page</button><button type="button" data-reticle-annotation-tab="history" aria-pressed="false">History</button></span>
|
|
74
|
+
<div data-reticle-current-annotation-actions class="reticle-annotation-actions" aria-label="Current page note actions">
|
|
75
|
+
<button type="button" ${MARKERS_BTN_ATTR} class="reticle-annotation-icon-btn reticle-annotation-marker-toggle" title="${markersLabel}" aria-label="${markersLabel}" aria-pressed="false" data-active="0" disabled>${hiToggleIconHtml(PresenterIcon.VIEW, ANNOTATION_ACTION_ICON_SIZE)}</button>
|
|
76
|
+
<button type="button" ${CLEAR_MARKS_ATTR} class="reticle-annotation-icon-btn" title="${clearLabel}" aria-label="${clearLabel}" disabled>${hiIconHtml(PresenterIcon.TRASH, ANNOTATION_ACTION_ICON_SIZE)}</button>
|
|
77
|
+
</div>
|
|
78
|
+
<button type="button" data-reticle-copy-all-notes class="reticle-annotation-icon-btn reticle-copy-all" title="${copyAllLabel}" aria-label="${copyAllLabel}">${hiIconHtml(PresenterIcon.COPY, ANNOTATION_ACTION_ICON_SIZE)}</button>
|
|
79
|
+
</div>
|
|
80
|
+
<div data-reticle-annotation-list class="reticle-annotation-list"></div>
|
|
81
|
+
</section>`;
|
|
82
|
+
export const CHAT_VIEWS_CSS = `
|
|
83
|
+
[data-reticle-chat-panel] .reticle-harness-spot{flex:none;border-bottom:1px solid var(--reticle-hud-border);padding:0 var(--reticle-hud-space-3);}
|
|
84
|
+
[data-reticle-chat-panel] .reticle-harness-spot[hidden]{display:none;}
|
|
85
|
+
[data-reticle-chat-panel] .reticle-harness-row{display:flex;align-items:center;gap:var(--reticle-hud-space-2);min-height:40px;}
|
|
86
|
+
[data-reticle-chat-panel] .reticle-harness-copy{display:flex;flex:1;min-width:0;flex-direction:column;line-height:1.3;}
|
|
87
|
+
[data-reticle-chat-panel] .reticle-harness-copy strong{font-size:var(--reticle-hud-size-sm);font-weight:600;color:var(--reticle-hud-text);}
|
|
88
|
+
[data-reticle-chat-panel] .reticle-harness-copy span{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--reticle-hud-size-xs);color:var(--reticle-hud-text-muted);}
|
|
89
|
+
[data-reticle-chat-panel] .reticle-harness-switch{flex:none;width:32px;height:20px;border:0;border-radius:20px;padding:2px;cursor:pointer;background:rgba(255,255,255,.2);}
|
|
90
|
+
[data-reticle-chat-panel] .reticle-harness-switch::after{content:"";display:block;width:16px;height:16px;border-radius:50%;background:#fff;transition:transform .15s;}
|
|
91
|
+
[data-reticle-chat-panel] .reticle-harness-switch[aria-checked="true"]{background:var(--reticle-accent);}
|
|
92
|
+
[data-reticle-chat-panel] .reticle-harness-switch[aria-checked="true"]::after{transform:translateX(12px);}
|
|
93
|
+
[data-reticle-chat-panel] .reticle-harness-switch:disabled{opacity:.45;cursor:not-allowed;}
|
|
94
|
+
[data-reticle-chat-panel] .reticle-harness-link{flex:none;color:var(--reticle-hud-brand);font-size:var(--reticle-hud-size-xs);font-weight:600;text-decoration:none;white-space:nowrap;}
|
|
95
|
+
[data-reticle-chat-panel] .reticle-harness-link:hover{text-decoration:underline;}
|
|
96
|
+
[data-reticle-hud] .reticle-chat-nav{display:contents;}
|
|
97
|
+
[data-reticle-hud] .reticle-chat-nav button{position:relative;width:var(--reticle-hud-control-size);height:var(--reticle-hud-control-size);justify-self:center;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:var(--reticle-hud-radius-md);padding:0;background:transparent;color:var(--reticle-hud-text-muted);cursor:pointer;}
|
|
98
|
+
[data-reticle-hud] .reticle-chat-nav button:hover{background:var(--reticle-hud-hover);color:var(--reticle-hud-text);}
|
|
99
|
+
[data-reticle-hud] .reticle-chat-nav button[data-capture="1"]{color:var(--reticle-accent);box-shadow:inset 0 -2px var(--reticle-accent);}
|
|
100
|
+
[data-reticle-hud] .reticle-chat-nav button[aria-current="page"],[data-reticle-hud] .reticle-chat-nav button[data-active="1"]{background:var(--reticle-hud-inset);color:var(--reticle-hud-text);}
|
|
101
|
+
[data-reticle-hud] .reticle-chat-nav .reticle-hi-icon{opacity:.92;}
|
|
102
|
+
[data-reticle-hud] .reticle-chat-nav .reticle-nav-count:empty{display:none;}
|
|
103
|
+
[data-reticle-hud] .reticle-chat-nav .reticle-nav-count:not(:empty){position:absolute;top:0;right:0;min-width:13px;height:13px;display:inline-flex;align-items:center;justify-content:center;padding:0 3px;border-radius:99px;background:var(--reticle-accent);color:#fff;font-size:8px;font-weight:700;}
|
|
104
|
+
[data-reticle-hud] .reticle-chat-nav .reticle-nav-count[hidden]{display:none;}
|
|
105
|
+
[data-reticle-page-panel]{position:absolute;right:0;left:auto;bottom:calc(100% + 8px);z-index:6;box-sizing:border-box;width:var(--reticle-dock-w);max-width:min(var(--reticle-dock-w),calc(100vw - 16px));height:min(var(--reticle-chat-max-h,var(--reticle-chat-h)),calc(100vh - 120px));max-height:min(var(--reticle-chat-max-h,var(--reticle-chat-h)),calc(100vh - 120px));flex-direction:column;overflow:hidden;border-radius:var(--reticle-hud-radius-lg);${HUD_GLASS_PAINT}color:var(--reticle-hud-text);font-size:13px;line-height:1.5;pointer-events:auto;text-align:left;}
|
|
106
|
+
[data-reticle-page-panel][hidden]{display:none!important;}
|
|
107
|
+
[data-reticle-page-open="annotations"] [data-reticle-page-panel="annotations"],[data-reticle-page-open="flows"] [data-reticle-page-panel="flows"]{display:flex;}
|
|
108
|
+
[data-reticle-page-open="annotations"] [data-reticle-chat-panel],[data-reticle-page-open="flows"] [data-reticle-chat-panel]{display:none!important;}
|
|
109
|
+
[data-reticle-page-heading],.reticle-page-heading{display:flex;align-items:center;justify-content:space-between;min-height:42px;box-sizing:border-box;padding:7px 12px;border-bottom:1px solid var(--reticle-hud-border);}
|
|
110
|
+
.reticle-page-heading strong{font-size:12px;font-weight:600;}
|
|
111
|
+
.reticle-page-heading button{width:26px;height:26px;border:0;border-radius:6px;background:transparent;color:var(--reticle-hud-text-muted);font:inherit;font-size:19px;line-height:1;cursor:pointer;}
|
|
112
|
+
.reticle-page-heading button:hover{background:var(--reticle-hud-hover);color:var(--reticle-hud-text);}
|
|
113
|
+
.reticle-page-subtitle{flex:none;padding:5px 12px;border-bottom:1px solid var(--reticle-hud-border);color:var(--reticle-hud-text-muted);font-size:10px;}
|
|
114
|
+
.reticle-page-panel .reticle-all-flows,.reticle-page-panel .reticle-annotation-list{flex:1;min-height:0;overflow-y:auto;}
|
|
115
|
+
[data-reticle-page-panel="annotations"] .reticle-annotations-tabs{flex:none;}
|
|
116
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-list{flex:1;}
|
|
117
|
+
[data-reticle-chat-panel] .reticle-marks-row{display:none !important;}
|
|
118
|
+
[data-reticle-page-panel="annotations"] .reticle-annotations-tabs{display:flex;align-items:center;gap:2px;min-height:var(--reticle-hud-control-size);padding:var(--reticle-hud-space-1) var(--reticle-hud-space-2);border-bottom:1px solid var(--reticle-hud-border);}
|
|
119
|
+
[data-reticle-page-panel="annotations"] .reticle-annotations-tabs button{border:0;border-radius:var(--reticle-hud-radius-sm);background:transparent;color:var(--reticle-hud-text-muted);padding:var(--reticle-hud-space-1) var(--reticle-hud-space-2);font:inherit;font-size:var(--reticle-hud-size-xs);cursor:pointer;}
|
|
120
|
+
[data-reticle-page-panel="annotations"] .reticle-annotations-tabs button[aria-pressed="true"]{background:var(--reticle-hud-inset);color:var(--reticle-hud-text);}
|
|
121
|
+
[data-reticle-page-panel="annotations"] .reticle-annotations-tabs .reticle-add-notes{display:inline-flex;align-items:center;gap:4px;margin-left:5px;padding:5px 7px;border:1px solid var(--reticle-hud-border-strong);background:var(--reticle-hud-inset);color:var(--reticle-hud-text);font-weight:600;white-space:nowrap;}
|
|
122
|
+
[data-reticle-page-panel="annotations"] .reticle-annotations-tabs .reticle-add-notes[data-active="1"]{border-color:var(--reticle-accent);background:var(--reticle-accent-soft);color:var(--reticle-accent);}
|
|
123
|
+
[data-reticle-page-panel="annotations"] .reticle-add-notes-icon{display:inline-flex;align-items:center;}
|
|
124
|
+
[data-reticle-page-panel="annotations"] .reticle-annotations-tabs .reticle-copy-all{margin-left:auto;color:var(--reticle-hud-brand);white-space:nowrap;}
|
|
125
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-actions{display:flex;align-items:center;gap:0;margin-left:0;}
|
|
126
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-actions[hidden]{display:none;}
|
|
127
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-icon-btn{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:var(--reticle-hud-radius-sm);background:transparent;color:var(--reticle-hud-text-muted);cursor:pointer;}
|
|
128
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-icon-btn .reticle-hi-icon--solid{opacity:0;}
|
|
129
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-icon-btn:hover:not(:disabled){color:var(--reticle-hud-text);background:var(--reticle-hud-hover);}
|
|
130
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-icon-btn[data-active="1"]{color:var(--reticle-accent);background:var(--reticle-accent-soft);border-color:color-mix(in srgb,var(--reticle-accent) 40%,transparent);}
|
|
131
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-icon-btn:disabled{opacity:.35;cursor:not-allowed;}
|
|
132
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-list{flex:1;min-height:0;overflow-y:auto;padding:var(--reticle-hud-space-2) var(--reticle-hud-space-3);}
|
|
133
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-empty{padding:var(--reticle-hud-space-4) var(--reticle-hud-space-2);text-align:center;color:var(--reticle-hud-text-muted);font-size:var(--reticle-hud-size-sm);}
|
|
134
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-item{display:flex;align-items:start;gap:var(--reticle-hud-space-2);padding:var(--reticle-hud-space-2) 2px;border-bottom:1px solid var(--reticle-hud-border);}
|
|
135
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-content{flex:1;min-width:0;}
|
|
136
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-content strong{display:block;font-size:11px;font-weight:600;overflow-wrap:anywhere;}
|
|
137
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-content span{display:block;margin-top:3px;font-size:var(--reticle-hud-size-xs);color:var(--reticle-hud-text-muted);overflow-wrap:anywhere;}
|
|
138
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-item button{flex:none;border:1px solid var(--reticle-line);border-radius:6px;background:rgba(255,255,255,.04);color:var(--reticle-muted);font:inherit;font-size:10px;padding:4px 6px;cursor:pointer;}
|
|
139
|
+
[data-reticle-page-panel="annotations"] .reticle-annotation-item button:hover{color:#fff;background:rgba(255,255,255,.1);}
|
|
140
|
+
`;
|
|
141
|
+
export class ChatViews {
|
|
142
|
+
#root;
|
|
143
|
+
#view = 'activity';
|
|
144
|
+
#annotationTab = 'current';
|
|
145
|
+
#current = [];
|
|
146
|
+
#history = readHistory();
|
|
147
|
+
#account;
|
|
148
|
+
#harness;
|
|
149
|
+
#pendingHarness;
|
|
150
|
+
#verdicts = 0;
|
|
151
|
+
#onHarness;
|
|
152
|
+
#onImpact;
|
|
153
|
+
#onOpenChat;
|
|
154
|
+
#listeners;
|
|
155
|
+
constructor(onHarness, onImpact, onOpenChat) {
|
|
156
|
+
this.#onHarness = onHarness;
|
|
157
|
+
this.#onImpact = onImpact;
|
|
158
|
+
this.#onOpenChat = onOpenChat;
|
|
159
|
+
}
|
|
160
|
+
mount(root) {
|
|
161
|
+
this.#root = root;
|
|
162
|
+
this.#listeners = new AbortController();
|
|
163
|
+
const signal = this.#listeners.signal;
|
|
164
|
+
root.querySelectorAll('[data-reticle-chat-view-btn]').forEach((button) => button.addEventListener('click', () => {
|
|
165
|
+
const view = button.getAttribute('data-reticle-chat-view-btn');
|
|
166
|
+
this.#onOpenChat(view);
|
|
167
|
+
this.open(view);
|
|
168
|
+
}, { signal }));
|
|
169
|
+
root
|
|
170
|
+
.querySelector('[data-reticle-chat-impact]')
|
|
171
|
+
?.addEventListener('click', () => this.#onImpact(), { signal });
|
|
172
|
+
root.querySelector('[data-reticle-harness-spot]')?.addEventListener('click', (event) => {
|
|
173
|
+
const target = event.target;
|
|
174
|
+
if (!(target instanceof Element) ||
|
|
175
|
+
null === target.closest('[data-reticle-harness-switch]'))
|
|
176
|
+
return;
|
|
177
|
+
const toggle = target.closest('[data-reticle-harness-switch]');
|
|
178
|
+
if (null === toggle || toggle.disabled)
|
|
179
|
+
return;
|
|
180
|
+
const enabled = toggle.getAttribute('aria-checked') !== 'true';
|
|
181
|
+
this.#pendingHarness = enabled;
|
|
182
|
+
toggle.setAttribute('aria-checked', String(enabled));
|
|
183
|
+
toggle.disabled = true;
|
|
184
|
+
this.#onHarness(enabled);
|
|
185
|
+
}, { signal });
|
|
186
|
+
root.querySelectorAll('[data-reticle-annotation-tab]').forEach((button) => button.addEventListener('click', () => {
|
|
187
|
+
this.#annotationTab =
|
|
188
|
+
'history' === button.getAttribute('data-reticle-annotation-tab')
|
|
189
|
+
? 'history'
|
|
190
|
+
: 'current';
|
|
191
|
+
this.#paintAnnotations();
|
|
192
|
+
}, { signal }));
|
|
193
|
+
root.querySelector('[data-reticle-annotate-btn]')?.addEventListener('click', () => {
|
|
194
|
+
this.#annotationTab = 'current';
|
|
195
|
+
this.#paintAnnotations();
|
|
196
|
+
}, { signal });
|
|
197
|
+
root
|
|
198
|
+
.querySelector('[data-reticle-copy-all-notes]')
|
|
199
|
+
?.addEventListener('click', () => this.#copyAll(), { signal });
|
|
200
|
+
root
|
|
201
|
+
.querySelectorAll('[data-reticle-page-close]')
|
|
202
|
+
.forEach((button) => button.addEventListener('click', () => this.closePage(), { signal }));
|
|
203
|
+
root.querySelector('[data-reticle-annotation-list]')?.addEventListener('click', (event) => {
|
|
204
|
+
const target = event.target;
|
|
205
|
+
if (!(target instanceof Element))
|
|
206
|
+
return;
|
|
207
|
+
const button = target.closest('[data-reticle-copy-note]');
|
|
208
|
+
if (null === button)
|
|
209
|
+
return;
|
|
210
|
+
const index = Number(button.getAttribute('data-reticle-copy-note'));
|
|
211
|
+
if (!Number.isInteger(index))
|
|
212
|
+
return;
|
|
213
|
+
const item = this.#visibleAnnotations()[index];
|
|
214
|
+
if (item !== undefined)
|
|
215
|
+
this.#copy([item], 'pageUrl' in item ? item.pageUrl : location.href);
|
|
216
|
+
}, { signal });
|
|
217
|
+
this.open(this.#view);
|
|
218
|
+
this.#paintHarness();
|
|
219
|
+
this.paintImpact(this.#verdicts);
|
|
220
|
+
this.#paintAnnotations();
|
|
221
|
+
}
|
|
222
|
+
teardown() {
|
|
223
|
+
this.#listeners?.abort();
|
|
224
|
+
this.#listeners = undefined;
|
|
225
|
+
this.#root = undefined;
|
|
226
|
+
}
|
|
227
|
+
open(view) {
|
|
228
|
+
if (view !== 'activity' && view !== 'flows' && view !== 'annotations')
|
|
229
|
+
return;
|
|
230
|
+
this.#view = view;
|
|
231
|
+
const root = this.#root;
|
|
232
|
+
if (root === undefined)
|
|
233
|
+
return;
|
|
234
|
+
if ('activity' === view)
|
|
235
|
+
root.removeAttribute('data-reticle-page-open');
|
|
236
|
+
else
|
|
237
|
+
root.setAttribute('data-reticle-page-open', view);
|
|
238
|
+
const chat = root.querySelector('[data-reticle-chat-panel]');
|
|
239
|
+
if (chat !== null)
|
|
240
|
+
chat.hidden = view !== 'activity';
|
|
241
|
+
root.querySelectorAll('[data-reticle-page-panel]').forEach((panel) => {
|
|
242
|
+
panel.hidden = panel.getAttribute('data-reticle-page-panel') !== view;
|
|
243
|
+
});
|
|
244
|
+
this.#root?.querySelectorAll('[data-reticle-chat-view-btn]').forEach((button) => {
|
|
245
|
+
if (button.getAttribute('data-reticle-chat-view-btn') === view)
|
|
246
|
+
button.setAttribute('aria-current', 'page');
|
|
247
|
+
else
|
|
248
|
+
button.removeAttribute('aria-current');
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
closePage() {
|
|
252
|
+
const root = this.#root;
|
|
253
|
+
if (root === undefined)
|
|
254
|
+
return;
|
|
255
|
+
root.removeAttribute('data-reticle-page-open');
|
|
256
|
+
root.querySelectorAll('[data-reticle-page-panel]').forEach((panel) => {
|
|
257
|
+
panel.hidden = true;
|
|
258
|
+
});
|
|
259
|
+
this.#view = 'activity';
|
|
260
|
+
root.querySelectorAll('[data-reticle-chat-view-btn]').forEach((button) => {
|
|
261
|
+
button.removeAttribute('aria-current');
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
paintAccount(account) {
|
|
265
|
+
this.#account = account;
|
|
266
|
+
this.#paintHarness();
|
|
267
|
+
}
|
|
268
|
+
paintHarness(config) {
|
|
269
|
+
this.#harness = config;
|
|
270
|
+
this.#pendingHarness = undefined;
|
|
271
|
+
this.#paintHarness();
|
|
272
|
+
}
|
|
273
|
+
paintImpact(verdicts) {
|
|
274
|
+
this.#verdicts = verdicts;
|
|
275
|
+
const el = this.#root?.querySelector('[data-reticle-chat-verdicts]');
|
|
276
|
+
if (el !== null && el !== undefined)
|
|
277
|
+
el.textContent = verdicts > 0 ? `· ${String(verdicts)}` : '';
|
|
278
|
+
}
|
|
279
|
+
paintAnnotations(items) {
|
|
280
|
+
this.#current = [...items];
|
|
281
|
+
const pageUrl = location.href;
|
|
282
|
+
const byId = new Map(this.#history.map((item) => [item.id, item]));
|
|
283
|
+
for (const item of items)
|
|
284
|
+
byId.set(item.id, { ...item, pageUrl });
|
|
285
|
+
this.#history = [...byId.values()]
|
|
286
|
+
.sort((a, b) => b.createdAt - a.createdAt)
|
|
287
|
+
.slice(0, HISTORY_LIMIT);
|
|
288
|
+
saveHistory(this.#history);
|
|
289
|
+
const count = this.#root?.querySelector('[data-reticle-note-count]');
|
|
290
|
+
if (count !== null && count !== undefined) {
|
|
291
|
+
count.hidden = 0 === items.length;
|
|
292
|
+
count.textContent = String(items.length);
|
|
293
|
+
}
|
|
294
|
+
this.#paintAnnotations();
|
|
295
|
+
}
|
|
296
|
+
#paintHarness() {
|
|
297
|
+
const spot = this.#root?.querySelector('[data-reticle-harness-spot]');
|
|
298
|
+
if (null === spot || spot === undefined)
|
|
299
|
+
return;
|
|
300
|
+
const account = this.#account;
|
|
301
|
+
const config = this.#harness;
|
|
302
|
+
if (account === undefined || !account.signedIn) {
|
|
303
|
+
spot.hidden = true;
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
spot.hidden = false;
|
|
307
|
+
const base = platformBase(config, account);
|
|
308
|
+
const setupUrl = `${base}${HARNESS_SETUP_PATH}`;
|
|
309
|
+
const planUrl = `${base}${HARNESS_PLAN_PATH}`;
|
|
310
|
+
if (config === undefined) {
|
|
311
|
+
spot.innerHTML = `<div class="reticle-harness-row"><div class="reticle-harness-copy"><strong>Reticle Harness</strong><span>Link project to enable driving</span></div><button type="button" role="switch" data-reticle-harness-switch class="reticle-harness-switch" aria-label="Reticle Harness autonomous driving" aria-checked="false" aria-disabled="true" disabled></button><a class="reticle-harness-link" href="${setupUrl}" target="_blank" rel="noopener noreferrer">Set up ↗</a></div>`;
|
|
312
|
+
}
|
|
313
|
+
else if (!config.harnessEntitled) {
|
|
314
|
+
spot.innerHTML = `<div class="reticle-harness-row"><div class="reticle-harness-copy"><strong>Reticle Harness</strong><span>Describe a user and Reticle drives the whole journey for you</span></div><a class="reticle-harness-link" href="${planUrl}" target="_blank" rel="noopener noreferrer">See plans ↗</a></div>`;
|
|
315
|
+
}
|
|
316
|
+
else if (config.credits !== undefined && config.credits.used >= config.credits.limit) {
|
|
317
|
+
spot.innerHTML = `<div class="reticle-harness-row"><div class="reticle-harness-copy"><strong>Reticle Harness</strong><span>${creditsLeft(config.credits)}. They renew over 30 days.</span></div><a class="reticle-harness-link" href="${planUrl}" target="_blank" rel="noopener noreferrer">Get more with Pro ↗</a></div>`;
|
|
318
|
+
}
|
|
319
|
+
else if (false === config.providerReady) {
|
|
320
|
+
spot.innerHTML = `<div class="reticle-harness-row"><div class="reticle-harness-copy"><strong>Reticle Harness</strong><span>Choose a model provider to start driving</span></div><a class="reticle-harness-link" href="${setupUrl}" target="_blank" rel="noopener noreferrer">Set up ↗</a></div>`;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
spot.innerHTML = `<div class="reticle-harness-row"><div class="reticle-harness-copy"><strong>Reticle Harness</strong><span>${config.credits === undefined ? 'Autonomous checks' : creditsLeft(config.credits)}</span></div><button type="button" role="switch" data-reticle-harness-switch class="reticle-harness-switch" aria-label="Reticle Harness autonomous driving" aria-checked="${String(this.#pendingHarness ?? config.harnessEnabled)}" ${this.#pendingHarness === undefined ? '' : 'disabled'}></button></div>`;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
#visibleAnnotations() {
|
|
327
|
+
return 'history' === this.#annotationTab ? this.#history : this.#current;
|
|
328
|
+
}
|
|
329
|
+
#paintAnnotations() {
|
|
330
|
+
const root = this.#root;
|
|
331
|
+
if (root === undefined)
|
|
332
|
+
return;
|
|
333
|
+
const actions = root.querySelector('[data-reticle-current-annotation-actions]');
|
|
334
|
+
if (actions !== null)
|
|
335
|
+
actions.hidden = 'history' === this.#annotationTab;
|
|
336
|
+
root
|
|
337
|
+
.querySelectorAll('[data-reticle-annotation-tab]')
|
|
338
|
+
.forEach((button) => button.setAttribute('aria-pressed', String(button.getAttribute('data-reticle-annotation-tab') === this.#annotationTab)));
|
|
339
|
+
const list = root.querySelector('[data-reticle-annotation-list]');
|
|
340
|
+
if (null === list)
|
|
341
|
+
return;
|
|
342
|
+
list.replaceChildren();
|
|
343
|
+
const items = this.#visibleAnnotations();
|
|
344
|
+
if (0 === items.length) {
|
|
345
|
+
const empty = document.createElement('div');
|
|
346
|
+
empty.className = 'reticle-annotation-empty';
|
|
347
|
+
const title = document.createElement('strong');
|
|
348
|
+
const hint = document.createElement('span');
|
|
349
|
+
const history = 'history' === this.#annotationTab;
|
|
350
|
+
title.textContent = history ? NOTES_TEXT.HISTORY_EMPTY : NOTES_TEXT.PAGE_EMPTY;
|
|
351
|
+
hint.textContent = history ? NOTES_TEXT.HISTORY_HINT : NOTES_TEXT.PAGE_HINT;
|
|
352
|
+
empty.append(title, hint);
|
|
353
|
+
list.appendChild(empty);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
items.forEach((item, index) => {
|
|
357
|
+
const row = document.createElement('div');
|
|
358
|
+
row.className = 'reticle-annotation-item';
|
|
359
|
+
const content = document.createElement('div');
|
|
360
|
+
content.className = 'reticle-annotation-content';
|
|
361
|
+
const note = document.createElement('strong');
|
|
362
|
+
note.textContent = item.note;
|
|
363
|
+
const where = document.createElement('span');
|
|
364
|
+
where.textContent = `${item.label} · ${item.route}${item.source === undefined ? '' : ` · ${item.source}`}`;
|
|
365
|
+
content.append(note, where);
|
|
366
|
+
const copy = document.createElement('button');
|
|
367
|
+
copy.type = 'button';
|
|
368
|
+
copy.textContent = 'Copy';
|
|
369
|
+
copy.setAttribute('data-reticle-copy-note', String(index));
|
|
370
|
+
row.append(content, copy);
|
|
371
|
+
list.appendChild(row);
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
#copyAll() {
|
|
375
|
+
const items = this.#visibleAnnotations();
|
|
376
|
+
if (items.length > 0)
|
|
377
|
+
this.#copy(items, 'history' === this.#annotationTab ? location.origin : location.href);
|
|
378
|
+
}
|
|
379
|
+
#copy(items, pageUrl) {
|
|
380
|
+
void navigator.clipboard?.writeText(marksForAgent(items, pageUrl)).catch(() => undefined);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
@@ -10,6 +10,7 @@ export declare const BUSY_ON = "1";
|
|
|
10
10
|
export declare const BUSY_OFF = "0";
|
|
11
11
|
export interface PresenterOptions {
|
|
12
12
|
paceMs?: number;
|
|
13
|
+
onKill?: () => void;
|
|
13
14
|
now?: () => number;
|
|
14
15
|
idleAfterMs?: number;
|
|
15
16
|
glowFadeMs?: number;
|
|
@@ -81,8 +82,8 @@ export declare const SETTINGS_BTN_ATTR = "data-reticle-settings-btn";
|
|
|
81
82
|
export declare const SETTINGS_PANEL_ATTR = "data-reticle-settings-panel";
|
|
82
83
|
export declare const SETTINGS_CLOSE_ATTR = "data-reticle-settings-close";
|
|
83
84
|
export declare const SETTING_KEY_ATTR = "data-reticle-setting";
|
|
84
|
-
export declare const SETTINGS_STORAGE_KEY
|
|
85
|
-
export declare const MINIMISED_STORAGE_KEY
|
|
85
|
+
export declare const SETTINGS_STORAGE_KEY: "reticle-presenter-settings";
|
|
86
|
+
export declare const MINIMISED_STORAGE_KEY: "reticle-presenter-minimised";
|
|
86
87
|
export declare const AMBIENT_GLOW_ATTR = "data-reticle-ambient-glow";
|
|
87
88
|
export declare const LIVENESS_ATTR = "data-reticle-live";
|
|
88
89
|
export declare const BLOCK_ATTR = "data-reticle-block";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ReticleStorageKey } from '../storage-keys.js';
|
|
1
2
|
export const BorderMode = { SESSION: 'session', BUSY: 'busy' };
|
|
2
3
|
export const DEFAULT_BORDER_MODE = BorderMode.SESSION;
|
|
3
4
|
export const DATA_BUSY = 'data-busy';
|
|
@@ -60,8 +61,8 @@ export const SETTINGS_BTN_ATTR = 'data-reticle-settings-btn';
|
|
|
60
61
|
export const SETTINGS_PANEL_ATTR = 'data-reticle-settings-panel';
|
|
61
62
|
export const SETTINGS_CLOSE_ATTR = 'data-reticle-settings-close';
|
|
62
63
|
export const SETTING_KEY_ATTR = 'data-reticle-setting';
|
|
63
|
-
export const SETTINGS_STORAGE_KEY =
|
|
64
|
-
export const MINIMISED_STORAGE_KEY =
|
|
64
|
+
export const SETTINGS_STORAGE_KEY = ReticleStorageKey.PRESENTER_SETTINGS;
|
|
65
|
+
export const MINIMISED_STORAGE_KEY = ReticleStorageKey.PRESENTER_MINIMISED;
|
|
65
66
|
export const AMBIENT_GLOW_ATTR = 'data-reticle-ambient-glow';
|
|
66
67
|
export const LIVENESS_ATTR = 'data-reticle-live';
|
|
67
68
|
export const BLOCK_ATTR = 'data-reticle-block';
|
|
@@ -74,6 +75,6 @@ export const HUD_POS_X_VAR = '--reticle-hud-x';
|
|
|
74
75
|
export const HUD_POS_Y_VAR = '--reticle-hud-y';
|
|
75
76
|
export const HUD_DRAG_THRESHOLD_PX = 4;
|
|
76
77
|
export const HUD_DOCK_MARGIN_PX = 8;
|
|
77
|
-
export const HUD_DRAG_IGNORE_SEL = '[data-reticle-pause], [data-reticle-annotate-btn], [data-reticle-markers-btn], [data-reticle-clear-marks], [data-reticle-copy-marks], [data-reticle-end], [data-reticle-min-btn], [data-reticle-settings-btn], [data-reticle-settings-panel], [data-reticle-report-btn], [data-reticle-report-panel], [data-reticle-chat-panel], [data-reticle-chat-toggle], [data-reticle-workspace-btn], [data-reticle-workspace-menu], [data-reticle-copy], [data-reticle-export], input, textarea, select, a, .reticle-head-ctl, [data-reticle-tally], .reticle-maxhint';
|
|
78
|
+
export const HUD_DRAG_IGNORE_SEL = '[data-reticle-pause], [data-reticle-annotate-btn], [data-reticle-markers-btn], [data-reticle-clear-marks], [data-reticle-copy-marks], [data-reticle-end], [data-reticle-min-btn], [data-reticle-settings-btn], [data-reticle-settings-panel], [data-reticle-report-btn], [data-reticle-report-panel], [data-reticle-chat-panel], [data-reticle-chat-toggle], [data-reticle-workspace-btn], [data-reticle-workspace-menu], [data-reticle-copy], [data-reticle-export], .reticle-toolbar-chrome button, .reticle-toolbar-actions button, input, textarea, select, a, .reticle-head-ctl, [data-reticle-tally], .reticle-maxhint';
|
|
78
79
|
export const THROTTLED_ATTR = 'data-reticle-throttled';
|
|
79
80
|
export const Z_HUD_TOOLTIP = 100;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { HumanControlKind, PresenterTone, SessionState } from '@reticlehq/core';
|
|
2
2
|
export type { ControlIntent, ControlHandler } from './presenter-config.js';
|
|
3
3
|
export declare const ENDED_FADE_MS = 4000;
|
|
4
|
+
export declare function flowTitle(name: string): string;
|
|
4
5
|
export declare const CONTROLS_CSS: string;
|
|
5
|
-
export declare const
|
|
6
|
+
export declare const CONTROLS_STATUS_HTML: string;
|
|
6
7
|
export declare const CONTROLS_BANNER_HTML = "<div data-reticle-banner class=\"reticle-banner\">Session ended</div>";
|
|
7
8
|
export declare const CONTROLS_MARKS_HTML: string;
|
|
8
|
-
export declare const CONTROLS_FLOWS_HTML
|
|
9
|
+
export declare const CONTROLS_FLOWS_HTML: string;
|
|
9
10
|
export declare const CONTROLS_FOOT_HTML: string;
|
|
10
11
|
interface ControlPanelHost {
|
|
11
12
|
emit: (kind: HumanControlKind, text?: string) => void;
|
|
@@ -21,6 +22,7 @@ export declare class ControlPanel {
|
|
|
21
22
|
get state(): SessionState;
|
|
22
23
|
mount(root: HTMLElement, glow: HTMLElement | undefined): void;
|
|
23
24
|
teardown(): void;
|
|
25
|
+
setFlowProgress(args: Record<string, unknown>): void;
|
|
24
26
|
setFlows(flows: unknown): void;
|
|
25
27
|
refilterFlows(): void;
|
|
26
28
|
setState(state: SessionState, text?: string, tone?: PresenterTone): void;
|