@reticlehq/browser 3.6.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/actions/action-report.d.ts +54 -0
  2. package/dist/actions/action-report.js +60 -0
  3. package/dist/actions/actions-dom.d.ts +1 -0
  4. package/dist/actions/actions-dom.js +12 -0
  5. package/dist/actions/actions-press.d.ts +1 -0
  6. package/dist/actions/actions-press.js +25 -1
  7. package/dist/actions/actions.d.ts +1 -37
  8. package/dist/actions/actions.js +24 -66
  9. package/dist/actions/appeared-text.js +3 -0
  10. package/dist/actions/danger-context.d.ts +2 -0
  11. package/dist/actions/danger-context.js +28 -2
  12. package/dist/actions/value-input.d.ts +1 -0
  13. package/dist/actions/value-input.js +11 -0
  14. package/dist/commands/commands.js +4 -0
  15. package/dist/dom/a11y.js +251 -10
  16. package/dist/dom/addressing/coverage-markers.d.ts +6 -0
  17. package/dist/dom/addressing/coverage-markers.js +13 -0
  18. package/dist/dom/dom-ignore.d.ts +2 -0
  19. package/dist/dom/dom-ignore.js +15 -2
  20. package/dist/dom/query.d.ts +1 -1
  21. package/dist/dom/query.js +78 -16
  22. package/dist/dom/render-page.d.ts +12 -0
  23. package/dist/dom/render-page.js +135 -0
  24. package/dist/dom/snapshot.js +55 -7
  25. package/dist/observers/dom.js +32 -16
  26. package/dist/observers/field.js +3 -21
  27. package/dist/observers/network.js +56 -7
  28. package/dist/observers/perf.js +53 -1
  29. package/dist/observers/route.js +6 -5
  30. package/dist/presenter/carousel/carousel.js +2 -7
  31. package/dist/presenter/carousel/panel-slides.d.ts +2 -4
  32. package/dist/presenter/carousel/panel-slides.js +17 -15
  33. package/dist/presenter/chrome/log-memory.d.ts +1 -0
  34. package/dist/presenter/chrome/presenter-log.d.ts +7 -0
  35. package/dist/presenter/chrome/presenter-log.js +48 -8
  36. package/dist/presenter/chrome/presenter-morph.d.ts +1 -0
  37. package/dist/presenter/chrome/presenter-morph.js +34 -0
  38. package/dist/presenter/chrome/presenter-report-copy.d.ts +17 -4
  39. package/dist/presenter/chrome/presenter-report-copy.js +26 -4
  40. package/dist/presenter/hud-telemetry.js +55 -4
  41. package/dist/presenter/presenter-account-styles.js +3 -3
  42. package/dist/presenter/presenter-account.d.ts +27 -5
  43. package/dist/presenter/presenter-account.js +83 -6
  44. package/dist/presenter/presenter-agent-link.d.ts +9 -0
  45. package/dist/presenter/presenter-agent-link.js +62 -0
  46. package/dist/presenter/presenter-chat-views.d.ts +27 -5
  47. package/dist/presenter/presenter-chat-views.js +312 -72
  48. package/dist/presenter/presenter-config.d.ts +2 -0
  49. package/dist/presenter/presenter-config.js +1 -0
  50. package/dist/presenter/presenter-controls.d.ts +0 -1
  51. package/dist/presenter/presenter-controls.js +13 -91
  52. package/dist/presenter/presenter-design-tokens.js +1 -1
  53. package/dist/presenter/presenter-frame.d.ts +1 -1
  54. package/dist/presenter/presenter-frame.js +8 -10
  55. package/dist/presenter/presenter-harness-row.d.ts +67 -0
  56. package/dist/presenter/presenter-harness-row.js +209 -0
  57. package/dist/presenter/presenter-personas.d.ts +35 -0
  58. package/dist/presenter/presenter-personas.js +95 -0
  59. package/dist/presenter/presenter-plan.js +25 -24
  60. package/dist/presenter/presenter-report-styles.js +40 -22
  61. package/dist/presenter/presenter-report.d.ts +2 -1
  62. package/dist/presenter/presenter-report.js +83 -17
  63. package/dist/presenter/presenter-settings-styles.js +8 -4
  64. package/dist/presenter/presenter-settings.d.ts +7 -6
  65. package/dist/presenter/presenter-settings.js +75 -34
  66. package/dist/presenter/presenter-shell-styles.js +12 -3
  67. package/dist/presenter/presenter-shell.d.ts +10 -4
  68. package/dist/presenter/presenter-shell.js +31 -23
  69. package/dist/presenter/presenter-styles.js +0 -2
  70. package/dist/presenter/presenter-workspace.js +10 -3
  71. package/dist/presenter/presenter.d.ts +3 -2
  72. package/dist/presenter/presenter.js +81 -20
  73. package/dist/registry/declared-platform.js +2 -0
  74. package/dist/reticle-inject.js +777 -700
  75. package/dist/reticle.js +36 -2
  76. package/dist/storage-keys.d.ts +3 -2
  77. package/dist/storage-keys.js +7 -3
  78. package/dist/transport/transport.js +5 -3
  79. package/dist/transport/unreachable-message.d.ts +1 -1
  80. package/dist/transport/unreachable-message.js +3 -5
  81. package/package.json +2 -2
  82. package/dist/presenter/carousel/offer-card.d.ts +0 -21
  83. package/dist/presenter/carousel/offer-card.js +0 -56
@@ -0,0 +1,95 @@
1
+ import { PERSONA_KEY_PREFIX } from '../storage-keys.js';
2
+ import { esc } from './chrome/presenter-safe-html.js';
3
+ export const CUSTOM_PERSONA = 'custom';
4
+ export const PERSONAS = [
5
+ {
6
+ id: 'first-time',
7
+ label: 'First-time visitor',
8
+ hint: 'starts from the first page, reads the labels and follows the obvious path',
9
+ },
10
+ {
11
+ id: 'power-user',
12
+ label: 'Returning power user',
13
+ hint: 'goes straight to the main task, takes shortcuts and repeats it quickly',
14
+ },
15
+ {
16
+ id: 'phone',
17
+ label: 'On a phone, slow connection',
18
+ hint: 'small-screen habits: taps, waits on loading, retries when nothing seems to happen',
19
+ },
20
+ {
21
+ id: 'keyboard',
22
+ label: 'Keyboard only',
23
+ hint: 'Tab, Enter and Escape only: focus order, traps and controls it cannot reach',
24
+ },
25
+ {
26
+ id: 'careless',
27
+ label: 'Careless user (bad and unexpected input)',
28
+ hint: 'empty fields, wrong formats, very long text, double submits, going back mid-flow',
29
+ },
30
+ {
31
+ id: 'admin',
32
+ label: 'Admin / settings',
33
+ hint: 'changes settings and permissions, then checks they stick after a reload',
34
+ },
35
+ ];
36
+ export const DEFAULT_PERSONA = PERSONAS[0].id;
37
+ const TEXT = {
38
+ LABEL: 'As',
39
+ CUSTOM: 'Custom…',
40
+ CUSTOM_SHORT: 'Custom',
41
+ CUSTOM_HINT: 'Describe who to be or what to try, in your own words.',
42
+ CUSTOM_PLACEHOLDER: 'e.g. a first-time shopper paying by card',
43
+ };
44
+ export const PERSONA_PICK_ID = 'reticle-harness-persona-pick';
45
+ const PERSONA_TEXT_ID = 'reticle-harness-persona';
46
+ function presetOf(pick) {
47
+ return PERSONAS.find((persona) => persona.id === pick);
48
+ }
49
+ export function personaText(pick, custom) {
50
+ const preset = presetOf(pick);
51
+ if (preset !== undefined)
52
+ return `${preset.label}: ${preset.hint}`;
53
+ const own = custom.trim();
54
+ return 0 === own.length ? undefined : own;
55
+ }
56
+ export function personaLabel(pick) {
57
+ return presetOf(pick)?.label ?? TEXT.CUSTOM_SHORT;
58
+ }
59
+ export function personaPickHtml(pick, disabled = false) {
60
+ const options = [
61
+ ...PERSONAS.map((p) => ({ id: p.id, label: p.label, hint: p.hint })),
62
+ { id: CUSTOM_PERSONA, label: TEXT.CUSTOM, hint: TEXT.CUSTOM_HINT },
63
+ ]
64
+ .map((o) => `<option value="${o.id}" title="${esc(o.hint)}"${o.id === pick ? ' selected' : ''}>${esc(o.label)}</option>`)
65
+ .join('');
66
+ const hint = esc(presetOf(pick)?.hint ?? TEXT.CUSTOM_HINT);
67
+ return (`<label class="reticle-harness-as" for="${PERSONA_PICK_ID}">${TEXT.LABEL}</label>` +
68
+ `<select id="${PERSONA_PICK_ID}" data-reticle-harness-persona-pick class="reticle-harness-persona" title="${hint}" aria-describedby="${PERSONA_PICK_ID}-hint"${disabled ? ' disabled' : ''}>${options}</select>` +
69
+ `<span id="${PERSONA_PICK_ID}-hint" class="reticle-sr">${hint}</span>`);
70
+ }
71
+ export function personaCustomHtml(pick, disabled = false) {
72
+ return CUSTOM_PERSONA === pick
73
+ ? `<input type="text" id="${PERSONA_TEXT_ID}" data-reticle-harness-persona class="reticle-harness-persona" aria-label="${TEXT.CUSTOM_HINT}" placeholder="${TEXT.CUSTOM_PLACEHOLDER}"${disabled ? ' disabled' : ''}>`
74
+ : '';
75
+ }
76
+ export function knownPick(value) {
77
+ return value !== null && value !== undefined && (CUSTOM_PERSONA === value || presetOf(value))
78
+ ? value
79
+ : undefined;
80
+ }
81
+ export function readPick(projectId) {
82
+ try {
83
+ return (knownPick(localStorage.getItem(`${PERSONA_KEY_PREFIX}${projectId ?? ''}`)) ?? DEFAULT_PERSONA);
84
+ }
85
+ catch {
86
+ return DEFAULT_PERSONA;
87
+ }
88
+ }
89
+ export function savePick(projectId, pick) {
90
+ try {
91
+ localStorage.setItem(`${PERSONA_KEY_PREFIX}${projectId ?? ''}`, pick);
92
+ }
93
+ catch {
94
+ }
95
+ }
@@ -17,32 +17,33 @@ const GLYPH = {
17
17
  [ScriptStatus.FAILED]: '✗',
18
18
  [ScriptStatus.BLOCKED]: '⊘',
19
19
  [ScriptStatus.NOT_TAKEN]: '–',
20
+ [ScriptStatus.UNDECIDED]: '?',
20
21
  };
21
22
  export const PLAN_CSS = `
22
- [data-reticle-chat-panel] .reticle-plan{flex:none;margin:0 10px 8px;padding:8px 10px;border:1px solid var(--reticle-hud-border);border-radius:10px;background:rgba(255,255,255,.03);}
23
- [data-reticle-chat-panel] .reticle-plan[hidden]{display:none;}
24
- [data-reticle-chat-panel] .reticle-plan-head{display:flex;align-items:center;gap:8px;margin-bottom:6px;font-size:var(--reticle-hud-size-xs);color:var(--reticle-hud-text-muted);}
25
- [data-reticle-chat-panel] .reticle-plan-head strong{color:var(--reticle-hud-text);font-size:var(--reticle-hud-size-sm);font-weight:600;}
26
- [data-reticle-chat-panel] .reticle-plan-head span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
27
- [data-reticle-chat-panel] .reticle-plan-close{flex:none;border:0;background:none;color:inherit;cursor:pointer;font-size:14px;line-height:1;padding:2px 4px;}
28
- [data-reticle-chat-panel] .reticle-plan-lanes{display:flex;flex-direction:column;gap:6px;max-height:240px;overflow:auto;scrollbar-width:none;}
29
- [data-reticle-chat-panel] .reticle-plan-lanes::-webkit-scrollbar{display:none;}
30
- [data-reticle-chat-panel] .reticle-plan-lane{display:flex;gap:6px;align-items:flex-start;min-width:0;}
31
- [data-reticle-chat-panel] .reticle-plan-lane-name{flex:none;width:16px;padding-top:6px;font-size:10px;font-weight:600;text-align:center;color:var(--reticle-hud-text-muted);}
32
- [data-reticle-chat-panel] .reticle-plan-lane-journeys{display:flex;flex:1;min-width:0;flex-direction:column;gap:4px;}
33
- [data-reticle-chat-panel] .reticle-plan-journey{display:block;width:100%;text-align:left;border:1px solid transparent;border-radius:8px;padding:5px 7px;background:rgba(255,255,255,.04);color:var(--reticle-hud-text);font:inherit;font-size:var(--reticle-hud-size-xs);cursor:pointer;}
34
- [data-reticle-chat-panel] .reticle-plan-journey[data-status="running"]{border-color:var(--reticle-c-active);box-shadow:0 0 12px -4px var(--reticle-c-active);}
35
- [data-reticle-chat-panel] .reticle-plan-journey[data-status="blocked"],[data-reticle-chat-panel] .reticle-plan-journey[data-status="not-taken"]{opacity:.55;}
36
- [data-reticle-chat-panel] .reticle-plan-row{display:flex;gap:6px;align-items:baseline;min-width:0;}
37
- [data-reticle-chat-panel] .reticle-plan-row b{flex:1;min-width:0;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
38
- [data-reticle-chat-panel] .reticle-plan-glyph{flex:none;width:12px;text-align:center;}
39
- [data-reticle-chat-panel] [data-status="running"]>.reticle-plan-row>.reticle-plan-glyph,[data-reticle-chat-panel] .reticle-plan-step[data-status="running"]>.reticle-plan-glyph{color:var(--reticle-c-active);animation:reticle-flow-pulse 1.2s ease-in-out infinite;}
40
- [data-reticle-chat-panel] [data-status="passed"]>.reticle-plan-row>.reticle-plan-glyph,[data-reticle-chat-panel] .reticle-plan-step[data-status="passed"]>.reticle-plan-glyph{color:#4ade80;}
41
- [data-reticle-chat-panel] [data-status="failed"]>.reticle-plan-row>.reticle-plan-glyph,[data-reticle-chat-panel] .reticle-plan-step[data-status="failed"]>.reticle-plan-glyph{color:#f87171;}
42
- [data-reticle-chat-panel] .reticle-plan-meta{display:block;margin:2px 0 0 18px;color:var(--reticle-hud-text-muted);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
43
- [data-reticle-chat-panel] .reticle-plan-steps{margin:4px 0 0 18px;display:flex;flex-direction:column;gap:2px;}
44
- [data-reticle-chat-panel] .reticle-plan-step{display:flex;gap:6px;color:var(--reticle-hud-text-muted);font-size:10px;min-width:0;}
45
- [data-reticle-chat-panel] .reticle-plan-step span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
23
+ [data-reticle-page-panel="harness"] .reticle-plan{flex:none;margin:0 10px 8px;padding:8px 10px;border:1px solid var(--reticle-hud-border);border-radius:10px;background:rgba(255,255,255,.03);}
24
+ [data-reticle-page-panel="harness"] .reticle-plan[hidden]{display:none;}
25
+ [data-reticle-page-panel="harness"] .reticle-plan-head{display:flex;align-items:center;gap:8px;margin-bottom:6px;font-size:var(--reticle-hud-size-xs);color:var(--reticle-hud-text-muted);}
26
+ [data-reticle-page-panel="harness"] .reticle-plan-head strong{color:var(--reticle-hud-text);font-size:var(--reticle-hud-size-sm);font-weight:600;}
27
+ [data-reticle-page-panel="harness"] .reticle-plan-head span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
28
+ [data-reticle-page-panel="harness"] .reticle-plan-close{flex:none;border:0;background:none;color:inherit;cursor:pointer;font-size:14px;line-height:1;padding:2px 4px;}
29
+ [data-reticle-page-panel="harness"] .reticle-plan-lanes{display:flex;flex-direction:column;gap:6px;max-height:240px;overflow:auto;scrollbar-width:none;}
30
+ [data-reticle-page-panel="harness"] .reticle-plan-lanes::-webkit-scrollbar{display:none;}
31
+ [data-reticle-page-panel="harness"] .reticle-plan-lane{display:flex;gap:6px;align-items:flex-start;min-width:0;}
32
+ [data-reticle-page-panel="harness"] .reticle-plan-lane-name{flex:none;width:16px;padding-top:6px;font-size:11px;font-weight:600;text-align:center;color:var(--reticle-hud-text-muted);}
33
+ [data-reticle-page-panel="harness"] .reticle-plan-lane-journeys{display:flex;flex:1;min-width:0;flex-direction:column;gap:4px;}
34
+ [data-reticle-page-panel="harness"] .reticle-plan-journey{display:block;width:100%;text-align:left;border:1px solid transparent;border-radius:8px;padding:5px 7px;background:rgba(255,255,255,.04);color:var(--reticle-hud-text);font:inherit;font-size:var(--reticle-hud-size-xs);cursor:pointer;}
35
+ [data-reticle-page-panel="harness"] .reticle-plan-journey[data-status="running"]{border-color:var(--reticle-c-active);box-shadow:0 0 12px -4px var(--reticle-c-active);}
36
+ [data-reticle-page-panel="harness"] .reticle-plan-journey[data-status="blocked"],[data-reticle-page-panel="harness"] .reticle-plan-journey[data-status="not-taken"]{opacity:.55;}
37
+ [data-reticle-page-panel="harness"] .reticle-plan-row{display:flex;gap:6px;align-items:baseline;min-width:0;}
38
+ [data-reticle-page-panel="harness"] .reticle-plan-row b{flex:1;min-width:0;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
39
+ [data-reticle-page-panel="harness"] .reticle-plan-glyph{flex:none;width:12px;text-align:center;}
40
+ [data-reticle-page-panel="harness"] [data-status="running"]>.reticle-plan-row>.reticle-plan-glyph,[data-reticle-page-panel="harness"] .reticle-plan-step[data-status="running"]>.reticle-plan-glyph{color:var(--reticle-c-active);animation:reticle-flow-pulse 1.2s ease-in-out infinite;}
41
+ [data-reticle-page-panel="harness"] [data-status="passed"]>.reticle-plan-row>.reticle-plan-glyph,[data-reticle-page-panel="harness"] .reticle-plan-step[data-status="passed"]>.reticle-plan-glyph{color:#4ade80;}
42
+ [data-reticle-page-panel="harness"] [data-status="failed"]>.reticle-plan-row>.reticle-plan-glyph,[data-reticle-page-panel="harness"] .reticle-plan-step[data-status="failed"]>.reticle-plan-glyph{color:#f87171;}
43
+ [data-reticle-page-panel="harness"] .reticle-plan-meta{display:block;margin:2px 0 0 18px;color:var(--reticle-hud-text-muted);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
44
+ [data-reticle-page-panel="harness"] .reticle-plan-steps{margin:4px 0 0 18px;display:flex;flex-direction:column;gap:2px;}
45
+ [data-reticle-page-panel="harness"] .reticle-plan-step{display:flex;gap:6px;color:var(--reticle-hud-text-muted);font-size:11px;min-width:0;}
46
+ [data-reticle-page-panel="harness"] .reticle-plan-step span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
46
47
  `;
47
48
  const STATUSES = new Set(Object.values(ScriptStatus));
48
49
  function statusOf(value) {
@@ -26,17 +26,17 @@ export const REPORT_CSS = `
26
26
  [${REPORT_PANEL_ATTR}] .reticle-report-scope{
27
27
  margin-left:auto;padding:3px 9px;border-radius:999px;cursor:pointer;
28
28
  border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.04);
29
- color:var(--reticle-muted);font:inherit;font-size:10.5px;}
29
+ color:var(--reticle-muted);font:inherit;font-size:11px;}
30
30
  [${REPORT_PANEL_ATTR}] .reticle-report-scope:hover{background:rgba(255,255,255,.08);color:var(--reticle-fg);}
31
31
  [${REPORT_PANEL_ATTR}] .reticle-report-close{
32
32
  flex:none;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;
33
33
  border:none;background:transparent;color:var(--reticle-faint);cursor:pointer;line-height:0;}
34
34
  [${REPORT_PANEL_ATTR}] .reticle-report-close svg{display:block;fill:none;stroke:currentColor;stroke-width:1.6;}
35
35
  [${REPORT_PANEL_ATTR}] .reticle-report-body{
36
- min-height:0;overflow-y:auto;padding:12px 14px 6px;
36
+ flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:12px 14px 6px;
37
37
  scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.14) transparent;}
38
38
  [${REPORT_PANEL_ATTR}] .reticle-report-empty{
39
- margin:0;padding:22px 6px;text-align:center;color:var(--reticle-faint);font-size:11.5px;}
39
+ margin:0;padding:22px 6px;text-align:center;color:var(--reticle-faint);font-size:12px;}
40
40
  /* The streak sits above the hero, as a flame and a number: it is the one stat that is about
41
41
  TODAY, so it reads first and never competes with the count it sits over. */
42
42
  [${REPORT_PANEL_ATTR}] .reticle-report-streak{
@@ -45,19 +45,36 @@ export const REPORT_CSS = `
45
45
  border:1px solid color-mix(in srgb,var(--reticle-c-active) 22%,transparent);
46
46
  font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;}
47
47
  [${REPORT_PANEL_ATTR}] .reticle-report-streak-label{
48
- color:var(--reticle-faint);font-size:9.5px;font-weight:400;letter-spacing:.04em;text-transform:uppercase;}
48
+ color:var(--reticle-faint);font-size:11px;font-weight:400;}
49
49
  [${REPORT_PANEL_ATTR}] .reticle-report-hero{display:flex;flex-direction:column;gap:2px;margin-bottom:10px;}
50
50
  [${REPORT_PANEL_ATTR}] .reticle-report-hero-value{
51
51
  font-size:34px;font-weight:700;line-height:1;letter-spacing:-.02em;color:var(--reticle-c-active);}
52
- [${REPORT_PANEL_ATTR}] .reticle-report-hero-label{color:var(--reticle-muted);font-size:11.5px;}
52
+ [${REPORT_PANEL_ATTR}] .reticle-report-hero-label{color:var(--reticle-muted);font-size:12px;}
53
53
  [${REPORT_PANEL_ATTR}] .reticle-report-verdicts{display:flex;gap:6px;margin-bottom:12px;}
54
54
  [${REPORT_PANEL_ATTR}] .reticle-sync-status{font-size:11px;color:var(--reticle-faint);font-variant-numeric:tabular-nums;white-space:nowrap;}
55
55
  [${REPORT_PANEL_ATTR}] .reticle-sync-status[data-reticle-sync-status="refused"]{color:var(--reticle-c-error,#f87171);}
56
56
  [${REPORT_PANEL_ATTR}] .reticle-report-coverage{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px;margin-bottom:12px;padding:8px 10px;border:1px solid var(--reticle-hud-border);border-radius:var(--reticle-hud-radius-sm,8px);}
57
57
  [${REPORT_PANEL_ATTR}] .reticle-report-coverage-value{font-size:18px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--reticle-hud-text);}
58
58
  [${REPORT_PANEL_ATTR}] .reticle-report-coverage-levels{display:flex;flex-wrap:wrap;gap:4px 10px;width:100%;font-size:11px;color:var(--reticle-faint);font-variant-numeric:tabular-nums;}
59
+ [${REPORT_PANEL_ATTR}] .reticle-report-instrumentation{margin-bottom:12px;padding:10px;border:1px solid var(--reticle-hud-border);border-radius:var(--reticle-hud-radius-md);}
60
+ [${REPORT_PANEL_ATTR}] .reticle-report-instrumentation-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;}
61
+ [${REPORT_PANEL_ATTR}] .reticle-report-instrumentation-head .reticle-report-section{margin-bottom:0;}
62
+ [${REPORT_PANEL_ATTR}] .reticle-report-instrumentation-value{font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--reticle-hud-text);}
63
+ [${REPORT_PANEL_ATTR}] .reticle-report-caps{display:grid;grid-template-columns:1fr 1fr;gap:4px 10px;margin:8px 0 0;padding:0;list-style:none;}
64
+ [${REPORT_PANEL_ATTR}] .reticle-report-cap{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 6px;min-width:0;font-size:11px;line-height:1.4;color:var(--reticle-muted);}
65
+ [${REPORT_PANEL_ATTR}] .reticle-report-cap-mark{flex:none;width:10px;text-align:center;}
66
+ [${REPORT_PANEL_ATTR}] .reticle-report-cap-name{flex:1;min-width:0;}
67
+ [${REPORT_PANEL_ATTR}] .reticle-report-cap[data-state="seen"] .reticle-report-cap-mark{color:#86efac;}
68
+ [${REPORT_PANEL_ATTR}] .reticle-report-cap[data-state="missing"]{grid-column:1/-1;color:var(--reticle-hud-text);}
69
+ [${REPORT_PANEL_ATTR}] .reticle-report-cap[data-state="missing"] .reticle-report-cap-mark{color:#fca5a5;}
70
+ [${REPORT_PANEL_ATTR}] .reticle-report-cap[data-state="unseen"]{color:var(--reticle-faint);}
71
+ [${REPORT_PANEL_ATTR}] .reticle-report-cap-cost{flex-basis:100%;padding-left:16px;color:var(--reticle-faint);}
72
+ [${REPORT_PANEL_ATTR}] .reticle-report-caps-note{display:block;margin-top:6px;color:var(--reticle-faint);font-size:11px;}
73
+ [${REPORT_PANEL_ATTR}] .reticle-report-copy-prompt{display:block;width:100%;margin-top:10px;padding:6px 10px;border:1px solid color-mix(in srgb,var(--reticle-hud-brand) 50%,transparent);
74
+ border-radius:var(--reticle-hud-radius-sm);background:var(--reticle-hud-brand-soft);color:var(--reticle-hud-brand);font:inherit;font-size:12px;font-weight:600;cursor:pointer;}
75
+ [${REPORT_PANEL_ATTR}] .reticle-report-copy-prompt:hover{filter:brightness(1.15);}
59
76
  [${REPORT_PANEL_ATTR}] .reticle-report-verdict{
60
- flex:1;padding:5px 8px;border-radius:8px;font-size:10.5px;text-align:center;
77
+ flex:1;padding:5px 8px;border-radius:8px;font-size:11px;text-align:center;
61
78
  background:rgba(255,255,255,.05);color:var(--reticle-muted);}
62
79
  [${REPORT_PANEL_ATTR}] .reticle-report-verdict[data-kind="fail"]{color:#fca5a5;}
63
80
  [${REPORT_PANEL_ATTR}] .reticle-report-verdict[data-kind="unknown"]{color:#fcd34d;}
@@ -67,11 +84,11 @@ export const REPORT_CSS = `
67
84
  display:flex;flex-direction:column;gap:2px;padding:8px;border-radius:10px;
68
85
  background:rgba(255,255,255,.04);}
69
86
  [${REPORT_PANEL_ATTR}] .reticle-report-value{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums;}
70
- [${REPORT_PANEL_ATTR}] .reticle-report-label{color:var(--reticle-faint);font-size:9.5px;line-height:1.3;}
87
+ [${REPORT_PANEL_ATTR}] .reticle-report-label{color:var(--reticle-faint);font-size:11px;line-height:1.3;}
71
88
  /* An estimate is labelled as one, and its label carries what it is measured against. */
72
89
  [${REPORT_PANEL_ATTR}] .reticle-report-basis{
73
90
  display:block;margin-top:2px;color:var(--reticle-c-active);opacity:.8;
74
- font-size:8.5px;letter-spacing:.06em;text-transform:uppercase;cursor:help;}
91
+ font-size:11px;letter-spacing:.06em;text-transform:uppercase;cursor:help;}
75
92
  [${REPORT_PANEL_ATTR}] .reticle-report-defects-wrap{margin-top:14px;}
76
93
  /* The heading and its push control on one line, so the button reads as belonging to this section
77
94
  rather than floating above the list. */
@@ -87,9 +104,9 @@ export const REPORT_CSS = `
87
104
  [${REPORT_PANEL_ATTR}] .reticle-report-defect-title{
88
105
  font-size:11px;line-height:1.35;overflow-wrap:anywhere;}
89
106
  [${REPORT_PANEL_ATTR}] .reticle-report-defect-detail{
90
- color:var(--reticle-faint);font-size:10px;line-height:1.35;overflow-wrap:anywhere;}
107
+ color:var(--reticle-faint);font-size:11px;line-height:1.35;overflow-wrap:anywhere;}
91
108
  [${REPORT_PANEL_ATTR}] .reticle-report-defect-source{
92
- color:var(--reticle-faint);font-size:9.5px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
109
+ color:var(--reticle-faint);font-size:11px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
93
110
  overflow-wrap:anywhere;}
94
111
  .reticle-report-defect-link{flex:none;display:inline-flex;align-items:center;justify-content:center;
95
112
  width:20px;height:20px;border-radius:6px;color:var(--reticle-faint);pointer-events:auto;
@@ -98,19 +115,19 @@ export const REPORT_CSS = `
98
115
  .reticle-report-defect-link:focus-visible{opacity:1;}
99
116
  .reticle-report-defect-link:hover{color:var(--reticle-fg);background:rgba(255,255,255,.07);}
100
117
  [${REPORT_PANEL_ATTR}] .reticle-report-defects-more{
101
- display:inline-block;margin-top:8px;font-size:10px;color:var(--reticle-c-active);
118
+ display:inline-block;margin-top:8px;font-size:11px;color:var(--reticle-c-active);
102
119
  text-decoration:none;}
103
120
  [${REPORT_PANEL_ATTR}] .reticle-report-defects-more:hover{text-decoration:underline;}
104
- [${REPORT_PANEL_ATTR}] .reticle-report-defects-all{display:inline-block;margin-top:8px;border:0;padding:0;background:none;cursor:pointer;font:inherit;font-size:10.5px;font-weight:500;color:var(--reticle-c-active);}
121
+ [${REPORT_PANEL_ATTR}] .reticle-report-defects-all{display:inline-block;margin-top:8px;border:0;padding:0;background:none;cursor:pointer;font:inherit;font-size:11px;font-weight:500;color:var(--reticle-c-active);}
105
122
  [${REPORT_PANEL_ATTR}] .reticle-report-defects-all:hover{text-decoration:underline;}
106
123
  [${REPORT_PANEL_ATTR}] .reticle-report-local-only{
107
124
  margin:14px 0 0;padding-top:10px;border-top:1px solid var(--reticle-line);
108
- color:var(--reticle-faint);font-size:10px;line-height:1.45;}
125
+ color:var(--reticle-faint);font-size:11px;line-height:1.45;}
109
126
  [${REPORT_PANEL_ATTR}] .reticle-report-local-only code{
110
127
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--reticle-c-active);}
111
128
  [${REPORT_PANEL_ATTR}] .reticle-report-chart-wrap{margin-top:12px;}
112
129
  [${REPORT_PANEL_ATTR}] .reticle-report-section{
113
- display:block;margin-bottom:6px;color:var(--reticle-faint);font-size:9.5px;
130
+ display:block;margin-bottom:6px;color:var(--reticle-faint);font-size:11px;
114
131
  letter-spacing:.06em;text-transform:uppercase;}
115
132
  /* Thirty fixed slots, not a flex row: one recorded day is one thin bar on a month's axis, and a
116
133
  single stretched block would read as "a month of solid work" on the day you install it. */
@@ -120,19 +137,20 @@ export const REPORT_CSS = `
120
137
  min-width:2px;border-radius:2px 2px 0 0;
121
138
  background:color-mix(in srgb,var(--reticle-c-active) 55%,transparent);}
122
139
  [${REPORT_PANEL_ATTR}] .reticle-report-bar[data-hot="1"]{background:#f87171;}
140
+ /* Sharing is a quiet row under the record, never the loudest thing on the panel. */
123
141
  [${REPORT_PANEL_ATTR}] .reticle-report-foot{
124
- flex:none;display:flex;flex-wrap:wrap;gap:6px;padding:10px 14px 8px;
142
+ flex:none;display:flex;flex-wrap:nowrap;align-items:center;gap:2px;padding:6px 10px 2px 14px;
125
143
  border-top:1px solid rgba(255,255,255,.06);}
144
+ [${REPORT_PANEL_ATTR}] .reticle-report-share-label{margin-right:4px;color:var(--reticle-faint);font-size:11px;}
126
145
  [${REPORT_PANEL_ATTR}] .reticle-report-share{
127
- padding:5px 10px;border-radius:8px;cursor:pointer;font:inherit;font-size:11px;
128
- border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.04);color:var(--reticle-muted);}
129
- [${REPORT_PANEL_ATTR}] .reticle-report-share:hover{background:rgba(255,255,255,.09);color:var(--reticle-fg);}
130
- [${REPORT_PANEL_ATTR}] .reticle-report-refer{
131
- border-color:color-mix(in srgb,var(--reticle-c-active) 45%,transparent);color:var(--reticle-fg);}
146
+ flex:none;padding:3px 6px;border:0;border-radius:6px;cursor:pointer;font:inherit;font-size:11px;
147
+ background:transparent;color:var(--reticle-muted);white-space:nowrap;}
148
+ [${REPORT_PANEL_ATTR}] .reticle-report-share:hover{background:rgba(255,255,255,.08);color:var(--reticle-fg);}
149
+ [${REPORT_PANEL_ATTR}] .reticle-report-refer{margin-left:auto;color:var(--reticle-hud-brand);}
132
150
  [${REPORT_PANEL_ATTR}] .reticle-report-links{
133
- flex:none;display:flex;gap:12px;padding:0 14px 12px;}
151
+ flex:none;display:flex;gap:12px;padding:2px 14px 10px;}
134
152
  [${REPORT_PANEL_ATTR}] .reticle-report-links a{
135
- color:var(--reticle-faint);font-size:10.5px;text-decoration:none;}
153
+ color:var(--reticle-faint);font-size:11px;text-decoration:none;}
136
154
  [${REPORT_PANEL_ATTR}] .reticle-report-links a:hover{color:var(--reticle-fg);text-decoration:underline;}
137
155
 
138
156
  /* Who this record belongs to, and the push-now control. Tokens only — no literal colours. */
@@ -1,6 +1,7 @@
1
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, account?: AccountState, projectName?: string, coverage?: Readonly<Record<string, number>>, sync?: Readonly<Record<string, unknown>>): string;
3
+ export declare function instrumentationHtml(instrumentation: Readonly<Record<string, unknown>> | undefined): string;
4
+ export declare function reportBodyHtml(scope: ImpactScope, dashboardUrl?: string, account?: AccountState, projectName?: string, coverage?: Readonly<Record<string, number>>, sync?: Readonly<Record<string, unknown>>, instrumentation?: Readonly<Record<string, unknown>>): string;
4
5
  interface ReportHost {
5
6
  onBeforeOpen?: () => void;
6
7
  onSyncNow?: () => void;
@@ -4,7 +4,7 @@ import { HUD_SURFACE_CLASS } from './chrome/presenter-hud-chrome.js';
4
4
  import { esc, isSafeDashboardUrl } from './chrome/presenter-safe-html.js';
5
5
  import { ACCOUNT_SIGNIN_ATTR, ACCOUNT_TEXT, SYNC_BTN_ATTR, accountControlHtml, syncButtonHtml, } from './presenter-account.js';
6
6
  import { REPORT_PANEL_ATTR, REPORT_ATTR, REPORT_CLOSE_ATTR } from './presenter-config.js';
7
- import { REPORT_LINKS, REPORT_TEXT, buildLinkedInShareUrl, buildReferralText, buildShareText, buildXShareUrl, compactDuration, compactNumber, COVERAGE_LEVELS, } from './chrome/presenter-report-copy.js';
7
+ import { REPORT_LINKS, REPORT_TEXT, buildLinkedInShareUrl, buildReferralText, buildShareText, buildXShareUrl, compactDuration, compactNumber, COVERAGE_LEVELS, CAPABILITY_WORDS, } from './chrome/presenter-report-copy.js';
8
8
  const SCOPE_ATTR = 'data-reticle-report-scope';
9
9
  const SCOPE = { PROJECT: 'project', MACHINE: 'machine' };
10
10
  const SHARE_X_ATTR = 'data-reticle-share-x';
@@ -22,9 +22,10 @@ export function reportPanelHtml() {
22
22
  <button type="button" ${REPORT_CLOSE_ATTR} class="reticle-report-close" title="Close" aria-label="Close impact">${close}</button>
23
23
  </div>
24
24
  <div class="reticle-report-body" data-reticle-report-body></div>
25
- <div class="reticle-report-foot">
26
- <button type="button" ${SHARE_X_ATTR} class="reticle-report-share">Post on X</button>
27
- <button type="button" ${SHARE_IN_ATTR} class="reticle-report-share">LinkedIn</button>
25
+ <div class="reticle-report-foot" role="group" aria-label="${REPORT_TEXT.SHARE_LABEL}">
26
+ <span class="reticle-report-share-label">${REPORT_TEXT.SHARE_LABEL}</span>
27
+ <button type="button" ${SHARE_X_ATTR} class="reticle-report-share">${REPORT_TEXT.POST_X}</button>
28
+ <button type="button" ${SHARE_IN_ATTR} class="reticle-report-share">${REPORT_TEXT.POST_IN}</button>
28
29
  <button type="button" ${SHARE_COPY_ATTR} class="reticle-report-share">${REPORT_TEXT.COPY}</button>
29
30
  <button type="button" ${REFER_ATTR} class="reticle-report-share reticle-report-refer">${REPORT_TEXT.REFER}</button>
30
31
  </div>
@@ -91,18 +92,76 @@ function syncStatusHtml(sync) {
91
92
  return '';
92
93
  const num = (key) => ('number' === typeof sync[key] ? sync[key] : 0);
93
94
  const status = sync['status'];
94
- const label = 'refused' === status
95
- ? `${String(num('refused'))} refused`
96
- : 'pending' === status
97
- ? `${String(num('pending'))} waiting`
98
- : 'on-platform' === status
99
- ? `Synced · ${String(num('onPlatform'))}`
100
- : undefined;
95
+ const keyRefused = 'string' === typeof sync['keyRefused'] ? sync['keyRefused'] : undefined;
96
+ const label = keyRefused !== undefined
97
+ ? REPORT_TEXT.KEY_REFUSED
98
+ : 'refused' === status
99
+ ? `${String(num('refused'))} refused`
100
+ : 'pending' === status
101
+ ? `${String(num('pending'))} waiting`
102
+ : 'on-platform' === status
103
+ ? `Synced · ${String(num('onPlatform'))}`
104
+ : 'local-only' === status
105
+ ? `${String(num('pending'))} ${REPORT_TEXT.NOT_SENT}`
106
+ : undefined;
101
107
  if (label === undefined)
102
108
  return '';
103
- const said = 'string' === typeof sync['said'] ? sync['said'] : '';
104
- return `<span class="reticle-sync-status" data-reticle-sync-status="${status}" title="${esc(said)}">${label}</span>`;
109
+ const said = keyRefused !== undefined
110
+ ? keyRefused
111
+ : 'local-only' === status
112
+ ? REPORT_TEXT.NOT_SENT_HELP
113
+ : 'string' === typeof sync['said']
114
+ ? sync['said']
115
+ : '';
116
+ const runUrl = sync['runUrl'];
117
+ const seeRun = 'string' === typeof runUrl && isSafeDashboardUrl(runUrl)
118
+ ? ` <a class="reticle-sync-run" data-reticle-link="run" href="${esc(runUrl)}" target="_blank" rel="noreferrer noopener">${REPORT_TEXT.SEE_RUN}</a>`
119
+ : '';
120
+ return `<span class="reticle-sync-status" data-reticle-sync-status="${esc(String(status))}" title="${esc(said)}">${label}</span>${seeRun}`;
121
+ }
122
+ const capabilityWords = (name) => 'string' === typeof name ? esc(CAPABILITY_WORDS[name] ?? name) : undefined;
123
+ function capabilityItem(state, name, cost = '') {
124
+ const mark = 'seen' === state ? '✓' : 'missing' === state ? '✕' : '○';
125
+ const why = '' === cost ? '' : `<span class="reticle-report-cap-cost">${cost}</span>`;
126
+ return `<li class="reticle-report-cap" data-state="${state}"><span class="reticle-report-cap-mark" aria-hidden="true">${mark}</span><span class="reticle-report-cap-name">${name}</span>${why}</li>`;
127
+ }
128
+ export function instrumentationHtml(instrumentation) {
129
+ if (instrumentation === undefined)
130
+ return '';
131
+ const covered = instrumentation['covered'];
132
+ const total = instrumentation['total'];
133
+ if ('number' !== typeof covered || 'number' !== typeof total)
134
+ return '';
135
+ const list = (key) => {
136
+ const value = instrumentation[key];
137
+ return Array.isArray(value) ? value : [];
138
+ };
139
+ const seen = list('seen').flatMap((n) => {
140
+ const name = capabilityWords(n);
141
+ return name === undefined ? [] : [capabilityItem('seen', name)];
142
+ });
143
+ const missing = list('missing').flatMap((m) => {
144
+ if ('object' !== typeof m || null === m)
145
+ return [];
146
+ const gap = m;
147
+ const name = capabilityWords(gap['capability']);
148
+ const cost = 'string' === typeof gap['cost'] ? esc(gap['cost']) : '';
149
+ return name === undefined ? [] : [capabilityItem('missing', name, cost)];
150
+ });
151
+ const unseen = list('notSeenYet').flatMap((n) => {
152
+ const name = capabilityWords(n);
153
+ return name === undefined ? [] : [capabilityItem('unseen', name)];
154
+ });
155
+ const items = [...missing, ...seen, ...unseen];
156
+ const caps = 0 === items.length
157
+ ? ''
158
+ : `<ul class="reticle-report-caps">${items.join('')}</ul>${0 === unseen.length ? '' : `<span class="reticle-report-caps-note">○ ${REPORT_TEXT.NOT_SEEN_YET}</span>`}`;
159
+ const copy = 'string' === typeof instrumentation['prompt']
160
+ ? `<button type="button" class="reticle-report-copy-prompt" ${COPY_PROMPT_ATTR}>${REPORT_TEXT.COPY_PROMPT}</button>`
161
+ : '';
162
+ return `<div class="reticle-report-instrumentation" title="${REPORT_TEXT.INSTRUMENTATION_HELP}"><div class="reticle-report-instrumentation-head"><span class="reticle-report-section">${REPORT_TEXT.INSTRUMENTATION}</span><span class="reticle-report-instrumentation-value">${REPORT_TEXT.covered(Math.round(covered), Math.round(total))}</span></div>${caps}${copy}</div>`;
105
163
  }
164
+ const COPY_PROMPT_ATTR = 'data-reticle-copy-prompt';
106
165
  function coverageHtml(coverage) {
107
166
  if (coverage === undefined)
108
167
  return '';
@@ -116,14 +175,14 @@ function coverageHtml(coverage) {
116
175
  .join('');
117
176
  return `<div class="reticle-report-coverage" title="${REPORT_TEXT.COVERAGE_HELP}"><span class="reticle-report-section">${REPORT_TEXT.COVERAGE}</span><span class="reticle-report-coverage-value">${head}</span><div class="reticle-report-coverage-levels">${rows}</div></div>`;
118
177
  }
119
- export function reportBodyHtml(scope, dashboardUrl, account, projectName, coverage, sync) {
178
+ export function reportBodyHtml(scope, dashboardUrl, account, projectName, coverage, sync, instrumentation) {
120
179
  const c = scope.counts;
121
180
  if (0 === c.calls)
122
181
  return `<p class="reticle-report-empty">${REPORT_TEXT.EMPTY}</p>`;
123
182
  const streak = scope.records.streakDays > 0
124
183
  ? `<span class="reticle-report-streak" title="Consecutive days with at least one verdict">🔥 ${String(scope.records.streakDays)} <span class="reticle-report-streak-label">${REPORT_TEXT.STREAK}</span></span>`
125
184
  : '';
126
- const hero = `<div class="reticle-report-hero"><span class="reticle-report-hero-value">${compactNumber(c.failed)}</span><span class="reticle-report-hero-label">${REPORT_TEXT.HERO_DEFECTS}</span></div>`;
185
+ const hero = `<div class="reticle-report-hero"><span class="reticle-report-hero-value">${compactNumber(c.failed)}</span><span class="reticle-report-hero-label">${REPORT_TEXT.heroDefects(c.failed)}</span></div>`;
127
186
  const verdicts = `<div class="reticle-report-verdicts" title="${REPORT_TEXT.UNKNOWN_HELP}">
128
187
  <span class="reticle-report-verdict" data-kind="pass">${compactNumber(c.passed)} ${REPORT_TEXT.PASSED}</span>
129
188
  <span class="reticle-report-verdict" data-kind="fail">${compactNumber(c.failed)} ${REPORT_TEXT.FAILED}</span>
@@ -140,7 +199,7 @@ export function reportBodyHtml(scope, dashboardUrl, account, projectName, covera
140
199
  card(compactDuration(scope.savings.minutes.value * 60_000), REPORT_TEXT.SAVED_MINUTES, scope.savings.minutes.basis),
141
200
  ].join('');
142
201
  const identity = `<div class="reticle-report-identity">${accountControlHtml(account, { dashboardUrl, projectName, verdicts: c.verdicts, defects: c.failed })}${syncButtonHtml(dashboardUrl)}${syncStatusHtml(sync)}</div>`;
143
- return `<div class="reticle-report-top">${streak}${identity}</div>${hero}${verdicts}${coverageHtml(coverage)}<div class="reticle-report-grid">${cards}</div>${defects(scope, dashboardUrl)}${chart(scope)}${localOnly(scope, dashboardUrl, account)}`;
202
+ return `<div class="reticle-report-top">${streak}${identity}</div>${hero}${verdicts}${instrumentationHtml(instrumentation)}${coverageHtml(coverage)}<div class="reticle-report-grid">${cards}</div>${defects(scope, dashboardUrl)}${chart(scope)}${localOnly(scope, dashboardUrl, account)}`;
144
203
  }
145
204
  function localOnly(scope, dashboardUrl, account) {
146
205
  if (dashboardUrl !== undefined)
@@ -212,6 +271,13 @@ export class PresenterReport {
212
271
  void this.#copy(ACCOUNT_TEXT.SIGNIN_COMMAND, signin);
213
272
  return;
214
273
  }
274
+ const copyPrompt = target.closest(`[${COPY_PROMPT_ATTR}]`);
275
+ const prompt = this.#snapshot?.instrumentation?.['prompt'];
276
+ if (copyPrompt !== null && 'string' === typeof prompt) {
277
+ e.stopPropagation();
278
+ void this.#copy(prompt, copyPrompt);
279
+ return;
280
+ }
215
281
  const sync = target.closest(`[${SYNC_BTN_ATTR}]`);
216
282
  if (sync !== null) {
217
283
  e.stopPropagation();
@@ -274,7 +340,7 @@ export class PresenterReport {
274
340
  this.#body.innerHTML =
275
341
  scope === undefined
276
342
  ? `<p class="reticle-report-empty">${REPORT_TEXT.EMPTY}</p>`
277
- : reportBodyHtml(scope, this.#snapshot?.dashboardUrl, this.#snapshot?.account, this.#snapshot?.projectName, this.#global ? undefined : this.#snapshot?.coverage, this.#global ? undefined : this.#snapshot?.sync);
343
+ : reportBodyHtml(scope, this.#snapshot?.dashboardUrl, this.#snapshot?.account, this.#snapshot?.projectName, this.#global ? undefined : this.#snapshot?.coverage, this.#global ? undefined : this.#snapshot?.sync, this.#global ? undefined : this.#snapshot?.instrumentation);
278
344
  }
279
345
  #openShare(url) {
280
346
  window.open(url, '_blank', 'noopener,noreferrer');
@@ -56,8 +56,10 @@ export const SETTINGS_CSS = `
56
56
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-row{
57
57
  display:flex;align-items:center;justify-content:space-between;gap:12px;
58
58
  padding:8px 14px;min-height:30px;}
59
+ [${SETTINGS_PANEL_ATTR}] .reticle-settings-labelcol{display:flex;flex:1;min-width:0;flex-direction:column;gap:2px;}
59
60
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-label{
60
- display:inline-flex;align-items:center;gap:6px;color:rgba(255,255,255,.62);font-size:13px;font-weight:500;}
61
+ display:inline-flex;align-items:center;gap:6px;color:rgba(255,255,255,.86);font-size:13px;font-weight:500;}
62
+ [${SETTINGS_PANEL_ATTR}] .reticle-settings-desc{color:rgba(255,255,255,.5);font-size:11px;line-height:1.35;}
61
63
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-help{
62
64
  display:inline-flex;align-items:center;justify-content:center;
63
65
  width:14px;height:14px;border:none;border-radius:999px;padding:0;cursor:help;
@@ -86,7 +88,7 @@ export const SETTINGS_CSS = `
86
88
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-toggle:focus-visible{outline:2px solid rgba(59,130,246,.55);outline-offset:2px;}
87
89
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-row[data-disabled="1"]{opacity:.45;pointer-events:none;}
88
90
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-section{
89
- padding:10px 14px 6px;color:rgba(255,255,255,.38);font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;}
91
+ padding:10px 14px 6px;color:rgba(255,255,255,.38);font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;}
90
92
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-swatches{
91
93
  display:flex;gap:8px;flex-wrap:wrap;padding:0 14px 10px;}
92
94
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-swatch{
@@ -98,13 +100,13 @@ export const SETTINGS_CSS = `
98
100
  border-color:#fff;box-shadow:0 0 0 1px rgba(0,0,0,.35);}
99
101
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-swatch:focus-visible{outline:2px solid rgba(59,130,246,.65);outline-offset:2px;}
100
102
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-checkrow{
101
- display:flex;align-items:center;gap:10px;padding:7px 14px;color:rgba(255,255,255,.8);font-size:13px;
103
+ display:flex;align-items:center;gap:10px;padding:7px 14px;color:rgba(255,255,255,.86);font-size:13px;
102
104
  cursor:pointer;user-select:none;margin:0;transition:background .12s;}
103
105
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-checkrow:hover{background:rgba(255,255,255,.03);}
104
106
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-check{
105
107
  width:16px;height:16px;border-radius:5px;border:1px solid rgba(255,255,255,.22);
106
108
  background:rgba(255,255,255,.04);display:inline-flex;align-items:center;justify-content:center;
107
- color:transparent;font-size:10px;line-height:1;flex:none;transition:background .12s,border-color .12s,color .12s;}
109
+ color:transparent;font-size:11px;line-height:1;flex:none;transition:background .12s,border-color .12s,color .12s;}
108
110
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-check[data-on="1"]{
109
111
  background:#fafafa;border-color:#fafafa;color:#111;}
110
112
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-check:focus-visible{outline:2px solid rgba(59,130,246,.55);outline-offset:2px;}
@@ -135,6 +137,8 @@ export const SETTINGS_CSS = `
135
137
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-kill[data-armed="1"]{background:#ef4444;border-color:#ef4444;color:#fff;}
136
138
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-kill:focus-visible{outline:2px solid rgba(239,68,68,.6);outline-offset:2px;}
137
139
  [${SETTINGS_PANEL_ATTR}] .reticle-settings-kill-sub{margin:8px 0 0;font-size:11px;line-height:1.45;color:rgba(255,255,255,.55);}
140
+ /* The SDK version line sits straight in the foot, so it takes the rows' inset rather than none. */
141
+ [${SETTINGS_PANEL_ATTR}] .reticle-settings-foot > .reticle-settings-kill-sub{padding:0 14px;}
138
142
  [${'data-reticle-overlay'}][${SETTINGS_ATTR}="1"] [${'data-reticle-hud'}] .reticle-tb-tip{
139
143
  opacity:0;visibility:hidden;transition-delay:0s;}
140
144
  /* The dock's accent IS the theme's active colour, published as --reticle-accent on the overlay by
@@ -1,5 +1,7 @@
1
1
  import type { HarnessConfig } from '@reticlehq/core';
2
+ import type { HarnessGateView } from './presenter-harness-row.js';
2
3
  import { SETTINGS_CSS } from './presenter-settings-styles.js';
4
+ import { type Credits } from '@reticlehq/core/hud';
3
5
  import type { AccountState } from '@reticlehq/core';
4
6
  import { type AccountDetails } from './presenter-account.js';
5
7
  export { SETTINGS_CSS };
@@ -41,12 +43,11 @@ export interface PresenterSettings {
41
43
  export declare function getPresenterSettings(): PresenterSettings;
42
44
  export declare function loadPresenterSettings(): PresenterSettings;
43
45
  export declare const SETTINGS_ACCOUNT_ATTR = "data-reticle-settings-account";
44
- export declare function creditsLeft(credits: {
45
- used: number;
46
- limit: number;
47
- } | undefined): string;
48
- export declare function paintHarnessRow(root: ParentNode, config: HarnessConfig | undefined): void;
46
+ export declare const HARNESS_LOCKED_HELP = "The Harness is not available to this workspace right now: see Plan in your Reticle dashboard.";
47
+ export declare function creditsLeft(credits: Credits | undefined): string;
48
+ export declare function paintHarnessRow(root: ParentNode, config: HarnessConfig | undefined, gate?: HarnessGateView): void;
49
49
  export declare function paintSettingsAccount(root: HTMLElement, account: AccountState | undefined, dashboardUrl: string | undefined, details?: AccountDetails): void;
50
+ export declare function paintSdkVersion(root: ParentNode, version: string | undefined): void;
50
51
  export declare function settingsPanelHtml(): string;
51
52
  export interface SettingsHost {
52
53
  onHideUntilRestart?: () => void;
@@ -62,7 +63,7 @@ export declare class PresenterSettingsPanel {
62
63
  constructor(host?: SettingsHost);
63
64
  contains(node: Node): boolean;
64
65
  mount(root: HTMLElement): void;
65
- paintHarness(config: HarnessConfig | undefined): void;
66
+ paintHarness(config: HarnessConfig | undefined, gate?: HarnessGateView): void;
66
67
  teardown(): void;
67
68
  isOpen(): boolean;
68
69
  open(): void;