@reticlehq/browser 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +17 -0
- package/dist/actions/actions-dom.d.ts +29 -0
- package/dist/actions/actions-dom.d.ts.map +1 -0
- package/dist/actions/actions-dom.js +153 -0
- package/dist/actions/actions-dom.js.map +1 -0
- package/dist/actions/actions.d.ts +92 -0
- package/dist/actions/actions.d.ts.map +1 -0
- package/dist/actions/actions.js +348 -0
- package/dist/actions/actions.js.map +1 -0
- package/dist/actions/scroll.d.ts +19 -0
- package/dist/actions/scroll.d.ts.map +1 -0
- package/dist/actions/scroll.js +44 -0
- package/dist/actions/scroll.js.map +1 -0
- package/dist/commands/commands.d.ts +5 -0
- package/dist/commands/commands.d.ts.map +1 -0
- package/dist/commands/commands.js +246 -0
- package/dist/commands/commands.js.map +1 -0
- package/dist/dom/a11y.d.ts +20 -0
- package/dist/dom/a11y.d.ts.map +1 -0
- package/dist/dom/a11y.js +263 -0
- package/dist/dom/a11y.js.map +1 -0
- package/dist/dom/auto-anchor.d.ts +66 -0
- package/dist/dom/auto-anchor.d.ts.map +1 -0
- package/dist/dom/auto-anchor.js +75 -0
- package/dist/dom/auto-anchor.js.map +1 -0
- package/dist/dom/dom-ignore.d.ts +7 -0
- package/dist/dom/dom-ignore.d.ts.map +1 -0
- package/dist/dom/dom-ignore.js +21 -0
- package/dist/dom/dom-ignore.js.map +1 -0
- package/dist/dom/query.d.ts +6 -0
- package/dist/dom/query.d.ts.map +1 -0
- package/dist/dom/query.js +236 -0
- package/dist/dom/query.js.map +1 -0
- package/dist/dom/refs.d.ts +15 -0
- package/dist/dom/refs.d.ts.map +1 -0
- package/dist/dom/refs.js +36 -0
- package/dist/dom/refs.js.map +1 -0
- package/dist/dom/snapshot.d.ts +22 -0
- package/dist/dom/snapshot.d.ts.map +1 -0
- package/dist/dom/snapshot.js +171 -0
- package/dist/dom/snapshot.js.map +1 -0
- package/dist/dom/theme.d.ts +26 -0
- package/dist/dom/theme.d.ts.map +1 -0
- package/dist/dom/theme.js +90 -0
- package/dist/dom/theme.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/observers/animation.d.ts +4 -0
- package/dist/observers/animation.d.ts.map +1 -0
- package/dist/observers/animation.js +35 -0
- package/dist/observers/animation.js.map +1 -0
- package/dist/observers/console.d.ts +4 -0
- package/dist/observers/console.d.ts.map +1 -0
- package/dist/observers/console.js +58 -0
- package/dist/observers/console.js.map +1 -0
- package/dist/observers/dom.d.ts +4 -0
- package/dist/observers/dom.d.ts.map +1 -0
- package/dist/observers/dom.js +96 -0
- package/dist/observers/dom.js.map +1 -0
- package/dist/observers/health.d.ts +8 -0
- package/dist/observers/health.d.ts.map +1 -0
- package/dist/observers/health.js +33 -0
- package/dist/observers/health.js.map +1 -0
- package/dist/observers/network.d.ts +11 -0
- package/dist/observers/network.d.ts.map +1 -0
- package/dist/observers/network.js +128 -0
- package/dist/observers/network.js.map +1 -0
- package/dist/observers/route.d.ts +4 -0
- package/dist/observers/route.d.ts.map +1 -0
- package/dist/observers/route.js +56 -0
- package/dist/observers/route.js.map +1 -0
- package/dist/observers/scroll.d.ts +4 -0
- package/dist/observers/scroll.d.ts.map +1 -0
- package/dist/observers/scroll.js +42 -0
- package/dist/observers/scroll.js.map +1 -0
- package/dist/observers/types.d.ts +6 -0
- package/dist/observers/types.d.ts.map +1 -0
- package/dist/observers/types.js +2 -0
- package/dist/observers/types.js.map +1 -0
- package/dist/presenter/overlay.d.ts +12 -0
- package/dist/presenter/overlay.d.ts.map +1 -0
- package/dist/presenter/overlay.js +31 -0
- package/dist/presenter/overlay.js.map +1 -0
- package/dist/presenter/presenter-config.d.ts +86 -0
- package/dist/presenter/presenter-config.d.ts.map +1 -0
- package/dist/presenter/presenter-config.js +51 -0
- package/dist/presenter/presenter-config.js.map +1 -0
- package/dist/presenter/presenter-controls.d.ts +74 -0
- package/dist/presenter/presenter-controls.d.ts.map +1 -0
- package/dist/presenter/presenter-controls.js +360 -0
- package/dist/presenter/presenter-controls.js.map +1 -0
- package/dist/presenter/presenter-effects.d.ts +14 -0
- package/dist/presenter/presenter-effects.d.ts.map +1 -0
- package/dist/presenter/presenter-effects.js +40 -0
- package/dist/presenter/presenter-effects.js.map +1 -0
- package/dist/presenter/presenter-glow.d.ts +43 -0
- package/dist/presenter/presenter-glow.d.ts.map +1 -0
- package/dist/presenter/presenter-glow.js +126 -0
- package/dist/presenter/presenter-glow.js.map +1 -0
- package/dist/presenter/presenter-log.d.ts +43 -0
- package/dist/presenter/presenter-log.d.ts.map +1 -0
- package/dist/presenter/presenter-log.js +118 -0
- package/dist/presenter/presenter-log.js.map +1 -0
- package/dist/presenter/presenter-run-state.d.ts +48 -0
- package/dist/presenter/presenter-run-state.d.ts.map +1 -0
- package/dist/presenter/presenter-run-state.js +37 -0
- package/dist/presenter/presenter-run-state.js.map +1 -0
- package/dist/presenter/presenter-styles.d.ts +7 -0
- package/dist/presenter/presenter-styles.d.ts.map +1 -0
- package/dist/presenter/presenter-styles.js +118 -0
- package/dist/presenter/presenter-styles.js.map +1 -0
- package/dist/presenter/presenter-tally.d.ts +20 -0
- package/dist/presenter/presenter-tally.d.ts.map +1 -0
- package/dist/presenter/presenter-tally.js +38 -0
- package/dist/presenter/presenter-tally.js.map +1 -0
- package/dist/presenter/presenter-verbs.d.ts +2 -0
- package/dist/presenter/presenter-verbs.d.ts.map +1 -0
- package/dist/presenter/presenter-verbs.js +29 -0
- package/dist/presenter/presenter-verbs.js.map +1 -0
- package/dist/presenter/presenter.d.ts +89 -0
- package/dist/presenter/presenter.d.ts.map +1 -0
- package/dist/presenter/presenter.js +428 -0
- package/dist/presenter/presenter.js.map +1 -0
- package/dist/recorder/recorder-styles.d.ts +12 -0
- package/dist/recorder/recorder-styles.d.ts.map +1 -0
- package/dist/recorder/recorder-styles.js +45 -0
- package/dist/recorder/recorder-styles.js.map +1 -0
- package/dist/recorder/recorder.d.ts +60 -0
- package/dist/recorder/recorder.d.ts.map +1 -0
- package/dist/recorder/recorder.js +436 -0
- package/dist/recorder/recorder.js.map +1 -0
- package/dist/registry/adapters.d.ts +31 -0
- package/dist/registry/adapters.d.ts.map +1 -0
- package/dist/registry/adapters.js +47 -0
- package/dist/registry/adapters.js.map +1 -0
- package/dist/registry/capabilities.d.ts +25 -0
- package/dist/registry/capabilities.d.ts.map +1 -0
- package/dist/registry/capabilities.js +48 -0
- package/dist/registry/capabilities.js.map +1 -0
- package/dist/registry/commit-and-signal.d.ts +9 -0
- package/dist/registry/commit-and-signal.d.ts.map +1 -0
- package/dist/registry/commit-and-signal.js +12 -0
- package/dist/registry/commit-and-signal.js.map +1 -0
- package/dist/registry/domains.d.ts +15 -0
- package/dist/registry/domains.d.ts.map +1 -0
- package/dist/registry/domains.js +19 -0
- package/dist/registry/domains.js.map +1 -0
- package/dist/registry/emitter.d.ts +28 -0
- package/dist/registry/emitter.d.ts.map +1 -0
- package/dist/registry/emitter.js +27 -0
- package/dist/registry/emitter.js.map +1 -0
- package/dist/registry/stores.d.ts +9 -0
- package/dist/registry/stores.d.ts.map +1 -0
- package/dist/registry/stores.js +30 -0
- package/dist/registry/stores.js.map +1 -0
- package/dist/reticle-presenter-helpers.d.ts +19 -0
- package/dist/reticle-presenter-helpers.d.ts.map +1 -0
- package/dist/reticle-presenter-helpers.js +81 -0
- package/dist/reticle-presenter-helpers.js.map +1 -0
- package/dist/reticle.d.ts +113 -0
- package/dist/reticle.d.ts.map +1 -0
- package/dist/reticle.js +379 -0
- package/dist/reticle.js.map +1 -0
- package/dist/review/annotator.d.ts +36 -0
- package/dist/review/annotator.d.ts.map +1 -0
- package/dist/review/annotator.js +321 -0
- package/dist/review/annotator.js.map +1 -0
- package/dist/review/mark-anchor.d.ts +23 -0
- package/dist/review/mark-anchor.d.ts.map +1 -0
- package/dist/review/mark-anchor.js +74 -0
- package/dist/review/mark-anchor.js.map +1 -0
- package/dist/security/serialization.d.ts +6 -0
- package/dist/security/serialization.d.ts.map +1 -0
- package/dist/security/serialization.js +103 -0
- package/dist/security/serialization.js.map +1 -0
- package/dist/timers/clock.d.ts +6 -0
- package/dist/timers/clock.d.ts.map +1 -0
- package/dist/timers/clock.js +80 -0
- package/dist/timers/clock.js.map +1 -0
- package/dist/timers/native-timers.d.ts +37 -0
- package/dist/timers/native-timers.d.ts.map +1 -0
- package/dist/timers/native-timers.js +79 -0
- package/dist/timers/native-timers.js.map +1 -0
- package/dist/transport/transport.d.ts +54 -0
- package/dist/transport/transport.d.ts.map +1 -0
- package/dist/transport/transport.js +182 -0
- package/dist/transport/transport.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { EventType, REDACTED_VALUE } from '@reticlehq/core';
|
|
2
|
+
import { isSensitiveKey } from '../security/serialization.js';
|
|
3
|
+
/**
|
|
4
|
+
* Redact credential-bearing query params (`?access_token=…`, signed-URL keys, magic-link tokens) so
|
|
5
|
+
* they don't leak into the agent transcript / flow / run artifacts. Only the query string is rewritten
|
|
6
|
+
* — the path (relative or absolute) and any hash are preserved — and only when something actually
|
|
7
|
+
* matched, so non-sensitive URLs pass through byte-for-byte. Uses the shared `isSensitiveKey` regex.
|
|
8
|
+
*/
|
|
9
|
+
export function redactUrl(raw) {
|
|
10
|
+
const queryStart = raw.indexOf('?');
|
|
11
|
+
if (queryStart === -1)
|
|
12
|
+
return raw;
|
|
13
|
+
const base = raw.slice(0, queryStart);
|
|
14
|
+
const rest = raw.slice(queryStart + 1);
|
|
15
|
+
const hashStart = rest.indexOf('#');
|
|
16
|
+
const query = hashStart === -1 ? rest : rest.slice(0, hashStart);
|
|
17
|
+
const hash = hashStart === -1 ? '' : rest.slice(hashStart);
|
|
18
|
+
const params = new URLSearchParams(query);
|
|
19
|
+
let changed = false;
|
|
20
|
+
for (const key of [...params.keys()]) {
|
|
21
|
+
if (isSensitiveKey(key)) {
|
|
22
|
+
params.set(key, REDACTED_VALUE);
|
|
23
|
+
changed = true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return changed ? `${base}?${params.toString()}${hash}` : raw;
|
|
27
|
+
}
|
|
28
|
+
function urlOf(input) {
|
|
29
|
+
if (typeof input === 'string')
|
|
30
|
+
return input;
|
|
31
|
+
if (input instanceof URL)
|
|
32
|
+
return input.href;
|
|
33
|
+
return input.url;
|
|
34
|
+
}
|
|
35
|
+
function methodOf(input, init) {
|
|
36
|
+
if (init?.method !== undefined)
|
|
37
|
+
return init.method.toUpperCase();
|
|
38
|
+
if (input instanceof Request)
|
|
39
|
+
return input.method.toUpperCase();
|
|
40
|
+
return 'GET';
|
|
41
|
+
}
|
|
42
|
+
/** Patch fetch + XMLHttpRequest to emit net.request events. Fully reversible. */
|
|
43
|
+
export function installNetwork(emit) {
|
|
44
|
+
// Keep the true original for teardown identity, plus a window-bound copy to invoke
|
|
45
|
+
// (fetch throws "Illegal invocation" if called with the wrong `this`).
|
|
46
|
+
const origFetch = window.fetch;
|
|
47
|
+
const callFetch = origFetch.bind(window);
|
|
48
|
+
// Correlation id so a NET_PENDING (emitted at request START) can be matched to its
|
|
49
|
+
// NET_REQUEST completion. A request that never completes leaves an unmatched NET_PENDING —
|
|
50
|
+
// that is how a hung/in-flight request becomes observable (it never resolves, so the old
|
|
51
|
+
// completion-only emit saw nothing).
|
|
52
|
+
let seq = 0;
|
|
53
|
+
const nextId = () => `n${++seq}`;
|
|
54
|
+
window.fetch = async (input, init) => {
|
|
55
|
+
const id = nextId();
|
|
56
|
+
const start = performance.now();
|
|
57
|
+
const method = methodOf(input, init);
|
|
58
|
+
const url = redactUrl(urlOf(input));
|
|
59
|
+
emit(EventType.NET_PENDING, { id, method, url, initiator: 'fetch' });
|
|
60
|
+
try {
|
|
61
|
+
const res = await callFetch(input, init);
|
|
62
|
+
emit(EventType.NET_REQUEST, {
|
|
63
|
+
id,
|
|
64
|
+
method,
|
|
65
|
+
url,
|
|
66
|
+
status: res.status,
|
|
67
|
+
ok: res.ok,
|
|
68
|
+
durationMs: Math.round(performance.now() - start),
|
|
69
|
+
initiator: 'fetch',
|
|
70
|
+
});
|
|
71
|
+
return res;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
emit(EventType.NET_REQUEST, {
|
|
75
|
+
id,
|
|
76
|
+
method,
|
|
77
|
+
url,
|
|
78
|
+
status: 0,
|
|
79
|
+
ok: false,
|
|
80
|
+
error: error instanceof Error ? error.message : String(error),
|
|
81
|
+
durationMs: Math.round(performance.now() - start),
|
|
82
|
+
initiator: 'fetch',
|
|
83
|
+
});
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const meta = new WeakMap();
|
|
88
|
+
const proto = XMLHttpRequest.prototype;
|
|
89
|
+
/* eslint-disable @typescript-eslint/unbound-method -- captured to re-invoke via .call(this) */
|
|
90
|
+
const origOpen = proto.open;
|
|
91
|
+
const origSend = proto.send;
|
|
92
|
+
/* eslint-enable @typescript-eslint/unbound-method */
|
|
93
|
+
const callOpen = origOpen;
|
|
94
|
+
proto.open = function (method, url, ...rest) {
|
|
95
|
+
meta.set(this, {
|
|
96
|
+
id: nextId(),
|
|
97
|
+
method: method.toUpperCase(),
|
|
98
|
+
url: redactUrl(String(url)),
|
|
99
|
+
start: 0,
|
|
100
|
+
});
|
|
101
|
+
callOpen.call(this, method, url, ...rest);
|
|
102
|
+
};
|
|
103
|
+
proto.send = function (body) {
|
|
104
|
+
const m = meta.get(this);
|
|
105
|
+
if (m !== undefined) {
|
|
106
|
+
m.start = performance.now();
|
|
107
|
+
emit(EventType.NET_PENDING, { id: m.id, method: m.method, url: m.url, initiator: 'xhr' });
|
|
108
|
+
this.addEventListener('loadend', () => {
|
|
109
|
+
emit(EventType.NET_REQUEST, {
|
|
110
|
+
id: m.id,
|
|
111
|
+
method: m.method,
|
|
112
|
+
url: m.url,
|
|
113
|
+
status: this.status,
|
|
114
|
+
ok: this.status >= 200 && this.status < 400,
|
|
115
|
+
durationMs: Math.round(performance.now() - m.start),
|
|
116
|
+
initiator: 'xhr',
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
origSend.call(this, body ?? null);
|
|
121
|
+
};
|
|
122
|
+
return () => {
|
|
123
|
+
window.fetch = origFetch;
|
|
124
|
+
proto.open = origOpen;
|
|
125
|
+
proto.send = origSend;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/observers/network.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/observers/route.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAWjD,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA+CjD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { EventType } from '@reticlehq/core';
|
|
2
|
+
function snapshotLocation() {
|
|
3
|
+
return {
|
|
4
|
+
pathname: location.pathname,
|
|
5
|
+
search: location.search,
|
|
6
|
+
hash: location.hash,
|
|
7
|
+
href: location.href,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/** Patch the History API + listen to popstate/hashchange to emit route.change. */
|
|
11
|
+
export function installRoute(emit) {
|
|
12
|
+
// Keep the true originals for teardown identity; bound copies are used for invocation
|
|
13
|
+
// (History methods throw "Illegal invocation" if called with the wrong `this`).
|
|
14
|
+
/* eslint-disable @typescript-eslint/unbound-method -- captured to restore exact identity on teardown */
|
|
15
|
+
const origPush = history.pushState;
|
|
16
|
+
const origReplace = history.replaceState;
|
|
17
|
+
/* eslint-enable @typescript-eslint/unbound-method */
|
|
18
|
+
const callPush = origPush.bind(history);
|
|
19
|
+
const callReplace = origReplace.bind(history);
|
|
20
|
+
const fire = (from) => {
|
|
21
|
+
const to = snapshotLocation();
|
|
22
|
+
if (to.href === from)
|
|
23
|
+
return;
|
|
24
|
+
emit(EventType.ROUTE_CHANGE, {
|
|
25
|
+
from,
|
|
26
|
+
to: to.href,
|
|
27
|
+
pathname: to.pathname,
|
|
28
|
+
search: to.search,
|
|
29
|
+
hash: to.hash,
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
history.pushState = (data, unused, url) => {
|
|
33
|
+
const from = location.href;
|
|
34
|
+
callPush(data, unused, url ?? null);
|
|
35
|
+
fire(from);
|
|
36
|
+
};
|
|
37
|
+
history.replaceState = (data, unused, url) => {
|
|
38
|
+
const from = location.href;
|
|
39
|
+
callReplace(data, unused, url ?? null);
|
|
40
|
+
fire(from);
|
|
41
|
+
};
|
|
42
|
+
let lastHref = location.href;
|
|
43
|
+
const onNav = () => {
|
|
44
|
+
fire(lastHref);
|
|
45
|
+
lastHref = location.href;
|
|
46
|
+
};
|
|
47
|
+
window.addEventListener('popstate', onNav);
|
|
48
|
+
window.addEventListener('hashchange', onNav);
|
|
49
|
+
return () => {
|
|
50
|
+
history.pushState = origPush;
|
|
51
|
+
history.replaceState = origReplace;
|
|
52
|
+
window.removeEventListener('popstate', onNav);
|
|
53
|
+
window.removeEventListener('hashchange', onNav);
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../src/observers/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,SAAS,gBAAgB;IACvB,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;KACpB,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,sFAAsF;IACtF,gFAAgF;IAChF,wGAAwG;IACxG,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IACnC,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IACzC,qDAAqD;IACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE9C,MAAM,IAAI,GAAG,CAAC,IAAY,EAAQ,EAAE;QAClC,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;QAC9B,IAAI,EAAE,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO;QAC7B,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE;YAC3B,IAAI;YACJ,EAAE,EAAE,EAAE,CAAC,IAAI;YACX,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,IAAI,EAAE,EAAE,CAAC,IAAI;SACd,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO,CAAC,SAAS,GAAG,CAAC,IAAa,EAAE,MAAc,EAAE,GAAyB,EAAQ,EAAE;QACrF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,CAAC,CAAC;IACF,OAAO,CAAC,YAAY,GAAG,CAAC,IAAa,EAAE,MAAc,EAAE,GAAyB,EAAQ,EAAE;QACxF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,CAAC,CAAC;IAEF,IAAI,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC7B,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,IAAI,CAAC,QAAQ,CAAC,CAAC;QACf,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC3B,CAAC,CAAC;IACF,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAE7C,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC7B,OAAO,CAAC,YAAY,GAAG,WAAW,CAAC;QACnC,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,mBAAmB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll.d.ts","sourceRoot":"","sources":["../../src/observers/scroll.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKjD,8FAA8F;AAC9F,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,QAAQ,CA2ClD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { EventType } from '@reticlehq/core';
|
|
2
|
+
import { refs } from '../dom/refs.js';
|
|
3
|
+
const THROTTLE_MS = 100;
|
|
4
|
+
const REVEAL_SELECTOR = '[data-reticle-reveal], [data-reveal], section';
|
|
5
|
+
/** Observe scroll position + reveal-on-scroll for modern scroll-reactive UIs (plan/03 §8). */
|
|
6
|
+
export function installScroll(emit) {
|
|
7
|
+
let lastEmit = 0;
|
|
8
|
+
let lastY = 0;
|
|
9
|
+
const onScroll = () => {
|
|
10
|
+
const now = performance.now();
|
|
11
|
+
if (now - lastEmit < THROTTLE_MS)
|
|
12
|
+
return;
|
|
13
|
+
lastEmit = now;
|
|
14
|
+
const y = window.scrollY;
|
|
15
|
+
const max = Math.max(1, document.documentElement.scrollHeight - window.innerHeight);
|
|
16
|
+
emit(EventType.SCROLL_POSITION, {
|
|
17
|
+
x: window.scrollX,
|
|
18
|
+
y,
|
|
19
|
+
percent: Math.round((y / max) * 100),
|
|
20
|
+
direction: y >= lastY ? 'down' : 'up',
|
|
21
|
+
});
|
|
22
|
+
lastY = y;
|
|
23
|
+
};
|
|
24
|
+
window.addEventListener('scroll', onScroll, { passive: true });
|
|
25
|
+
let io;
|
|
26
|
+
if (typeof IntersectionObserver === 'function') {
|
|
27
|
+
io = new IntersectionObserver((entries) => {
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
if (entry.isIntersecting) {
|
|
30
|
+
emit(EventType.REVEAL_SHOWN, { ratio: entry.intersectionRatio }, refs.refFor(entry.target));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, { threshold: 0.25 });
|
|
34
|
+
for (const el of document.querySelectorAll(REVEAL_SELECTOR))
|
|
35
|
+
io.observe(el);
|
|
36
|
+
}
|
|
37
|
+
return () => {
|
|
38
|
+
window.removeEventListener('scroll', onScroll);
|
|
39
|
+
io?.disconnect();
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=scroll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll.js","sourceRoot":"","sources":["../../src/observers/scroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAGtC,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,eAAe,GAAG,+CAA+C,CAAC;AAExE,8FAA8F;AAC9F,MAAM,UAAU,aAAa,CAAC,IAAU;IACtC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC1B,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,GAAG,GAAG,QAAQ,GAAG,WAAW;YAAE,OAAO;QACzC,QAAQ,GAAG,GAAG,CAAC;QACf,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QACpF,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE;YAC9B,CAAC,EAAE,MAAM,CAAC,OAAO;YACjB,CAAC;YACD,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;YACpC,SAAS,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;SACtC,CAAC,CAAC;QACH,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC,CAAC;IACF,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,IAAI,EAAoC,CAAC;IACzC,IAAI,OAAO,oBAAoB,KAAK,UAAU,EAAE,CAAC;QAC/C,EAAE,GAAG,IAAI,oBAAoB,CAC3B,CAAC,OAAO,EAAE,EAAE;YACV,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;oBACzB,IAAI,CACF,SAAS,CAAC,YAAY,EACtB,EAAE,KAAK,EAAE,KAAK,CAAC,iBAAiB,EAAE,EAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAC1B,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC,EACD,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAC;QACF,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,gBAAgB,CAAC,eAAe,CAAC;YAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,GAAG,EAAE;QACV,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC/C,EAAE,EAAE,UAAU,EAAE,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { EventType } from '@reticlehq/core';
|
|
2
|
+
/** An observer emits normalized events; the orchestrator stamps time + forwards them. */
|
|
3
|
+
export type Emit = (type: EventType, data: Record<string, unknown>, ref?: string) => void;
|
|
4
|
+
/** Every observer returns a teardown that fully restores any patched globals. */
|
|
5
|
+
export type Teardown = () => void;
|
|
6
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/observers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,yFAAyF;AACzF,MAAM,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAE1F,iFAAiF;AACjF,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/observers/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface OverlayStats {
|
|
2
|
+
connected: boolean;
|
|
3
|
+
events: number;
|
|
4
|
+
}
|
|
5
|
+
export interface OverlayHandle {
|
|
6
|
+
update: (stats: OverlayStats) => void;
|
|
7
|
+
destroy: () => void;
|
|
8
|
+
}
|
|
9
|
+
/** A tiny in-page status chip: connection + event count. Off by default. */
|
|
10
|
+
export declare function installOverlay(): OverlayHandle;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=overlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/presenter/overlay.ts"],"names":[],"mappings":"AAAA,UAAU,YAAY;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAiBD,4EAA4E;AAC5E,wBAAgB,cAAc,IAAI,aAAa,CAc9C"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const STYLE = [
|
|
2
|
+
'position:fixed',
|
|
3
|
+
'bottom:8px',
|
|
4
|
+
'right:8px',
|
|
5
|
+
'z-index:2147483647',
|
|
6
|
+
'font:11px ui-monospace,SFMono-Regular,Menlo,monospace',
|
|
7
|
+
'background:#151823',
|
|
8
|
+
'color:#e6e9f0',
|
|
9
|
+
'border:1px solid #2a2f3d',
|
|
10
|
+
'border-radius:8px',
|
|
11
|
+
'padding:6px 10px',
|
|
12
|
+
'pointer-events:none',
|
|
13
|
+
'opacity:0.85',
|
|
14
|
+
].join(';');
|
|
15
|
+
/** A tiny in-page status chip: connection + event count. Off by default. */
|
|
16
|
+
export function installOverlay() {
|
|
17
|
+
const el = document.createElement('div');
|
|
18
|
+
el.setAttribute('data-reticle-overlay', '');
|
|
19
|
+
el.style.cssText = STYLE;
|
|
20
|
+
el.textContent = 'Reticle: connecting…';
|
|
21
|
+
document.body.appendChild(el);
|
|
22
|
+
return {
|
|
23
|
+
update: (stats) => {
|
|
24
|
+
el.textContent = `Reticle ${stats.connected ? '●' : '○'} ${String(stats.events)} events`;
|
|
25
|
+
},
|
|
26
|
+
destroy: () => {
|
|
27
|
+
el.remove();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/presenter/overlay.ts"],"names":[],"mappings":"AAUA,MAAM,KAAK,GAAG;IACZ,gBAAgB;IAChB,YAAY;IACZ,WAAW;IACX,oBAAoB;IACpB,uDAAuD;IACvD,oBAAoB;IACpB,eAAe;IACf,0BAA0B;IAC1B,mBAAmB;IACnB,kBAAkB;IAClB,qBAAqB;IACrB,cAAc;CACf,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,4EAA4E;AAC5E,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACzC,EAAE,CAAC,YAAY,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;IAC5C,EAAE,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;IACzB,EAAE,CAAC,WAAW,GAAG,sBAAsB,CAAC;IACxC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC9B,OAAO;QACL,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAChB,EAAE,CAAC,WAAW,GAAG,WAAW,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;QAC3F,CAAC;QACD,OAAO,EAAE,GAAG,EAAE;YACZ,EAAE,CAAC,MAAM,EAAE,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type ControlHandler } from './presenter-controls.js';
|
|
2
|
+
/**
|
|
3
|
+
* Presenter tunables + option surface. Split out of presenter.ts so that file is just the controller
|
|
4
|
+
* under the size cap; these are pure declarations (interfaces + named constants), no behavior. None
|
|
5
|
+
* cross the browser↔bridge↔agent wire, so they live here, not in @reticlehq/core.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Border behavior.
|
|
9
|
+
* - 'session': base border persists connect→disconnect; the busy machine drives only the shimmer.
|
|
10
|
+
* - 'busy': back-compat — the busy machine toggles the base border on/off.
|
|
11
|
+
*/
|
|
12
|
+
export declare const BorderMode: {
|
|
13
|
+
readonly SESSION: "session";
|
|
14
|
+
readonly BUSY: "busy";
|
|
15
|
+
};
|
|
16
|
+
export type BorderMode = (typeof BorderMode)[keyof typeof BorderMode];
|
|
17
|
+
export declare const DEFAULT_BORDER_MODE: BorderMode;
|
|
18
|
+
export declare const DATA_BUSY = "data-busy";
|
|
19
|
+
export declare const BUSY_ON = "1";
|
|
20
|
+
export declare const BUSY_OFF = "0";
|
|
21
|
+
export interface PresenterOptions {
|
|
22
|
+
paceMs?: number;
|
|
23
|
+
/** Injected monotonic clock for the glow state machine (tests drive transitions). */
|
|
24
|
+
now?: () => number;
|
|
25
|
+
/** Quiet window before busy -> fading. Overridable so tests run fast. */
|
|
26
|
+
idleAfterMs?: number;
|
|
27
|
+
/** Fade duration before fading -> idle (keep in sync with the glow CSS opacity transition). */
|
|
28
|
+
glowFadeMs?: number;
|
|
29
|
+
/** Liveness heartbeat interval (ms). Overridable so tests run fast. */
|
|
30
|
+
heartbeatMs?: number;
|
|
31
|
+
/** Quiet (ms) after which the act strip shows the live "idle · {duration}" clock. Test-overridable. */
|
|
32
|
+
idleNoticeMs?: number;
|
|
33
|
+
/** Quiet (ms) after which the session AUTO-ENDS (glow off, panel kept). Default 5min; agent-tunable. */
|
|
34
|
+
idleEndMs?: number;
|
|
35
|
+
/** Session id, surfaced in the exported run state. */
|
|
36
|
+
sessionId?: string;
|
|
37
|
+
/** Deprecated: accepted for source compat; the live log no longer auto-expires. */
|
|
38
|
+
narrationDwellMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* 'session' (default): base border persists connect→disconnect, busy machine drives only the
|
|
41
|
+
* shimmer. 'busy': back-compat — busy machine toggles the base border on/off.
|
|
42
|
+
*/
|
|
43
|
+
border?: BorderMode;
|
|
44
|
+
/** Max accumulated activity-log rows before the oldest are pruned. Default 50. */
|
|
45
|
+
logMax?: number;
|
|
46
|
+
/** Called when the human clicks pause/resume/end or sends a message from the panel. */
|
|
47
|
+
onControl?: ControlHandler;
|
|
48
|
+
/** Overridable ended-border fade delay (native timer). Default 4000. */
|
|
49
|
+
endedFadeMs?: number;
|
|
50
|
+
}
|
|
51
|
+
export declare const DEFAULT_PACE = 450;
|
|
52
|
+
/**
|
|
53
|
+
* Glow state machine phases (exposed via glowPhase() for tests). A burst of activity flips the
|
|
54
|
+
* border IN once on the first activity, holds steady (the slow reticle-pulse breathing keeps running
|
|
55
|
+
* uninterrupted — no per-action restart/strobe), then fades OUT once after a quiet window.
|
|
56
|
+
*/
|
|
57
|
+
export declare const GlowPhase: {
|
|
58
|
+
readonly IDLE: "idle";
|
|
59
|
+
readonly BUSY: "busy";
|
|
60
|
+
readonly FADING: "fading";
|
|
61
|
+
};
|
|
62
|
+
export type GlowPhase = (typeof GlowPhase)[keyof typeof GlowPhase];
|
|
63
|
+
/** Quiet window before busy -> fading. */
|
|
64
|
+
export declare const IDLE_AFTER_MS = 700;
|
|
65
|
+
/** Liveness heartbeat: how often the act strip refreshes its "idle · {duration}" clock. */
|
|
66
|
+
export declare const HEARTBEAT_MS = 1000;
|
|
67
|
+
/**
|
|
68
|
+
* After this much quiet, the act strip stops showing the last action and starts a LIVE, ticking
|
|
69
|
+
* "◌ idle · {duration} since last action" — so a watcher can tell a 3s think from a dead agent
|
|
70
|
+
* (the killer gap: a frozen panel used to look identical whether the agent paused or stopped).
|
|
71
|
+
*/
|
|
72
|
+
export declare const IDLE_NOTICE_MS = 4000;
|
|
73
|
+
/** Default session-idle-end: after this much quiet the session auto-ends (glow off, panel persists
|
|
74
|
+
* for analysis). Agent-tweakable via reticle_session { idleEndMs } for the app's needs. */
|
|
75
|
+
export declare const IDLE_END_MS = 300000;
|
|
76
|
+
/** Floor for a tweaked idle-end so the agent can't set a uselessly tiny window. */
|
|
77
|
+
export declare const IDLE_END_MIN_MS = 5000;
|
|
78
|
+
/** Must match the glow CSS opacity transition (.25s) so phase reaches idle after the fade paints. */
|
|
79
|
+
export declare const GLOW_FADE_MS = 250;
|
|
80
|
+
export declare const GLOW_ON = "1";
|
|
81
|
+
export declare const GLOW_OFF = "0";
|
|
82
|
+
export declare const DATA_ON = "data-on";
|
|
83
|
+
/** Overlay-root attribute toggled when the panel is minimised to a bar. */
|
|
84
|
+
export declare const MIN_ATTR = "data-reticle-min";
|
|
85
|
+
export declare const THROTTLED_ATTR = "data-reticle-throttled";
|
|
86
|
+
//# sourceMappingURL=presenter-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presenter-config.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D;;;;GAIG;AAEH;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CAAgD,CAAC;AACxE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AACtE,eAAO,MAAM,mBAAmB,EAAE,UAA+B,CAAC;AAClE,eAAO,MAAM,SAAS,cAAc,CAAC;AACrC,eAAO,MAAM,OAAO,MAAM,CAAC;AAC3B,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wGAAwG;IACxG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,MAAM,CAAC;AAEhC;;;;GAIG;AACH,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEnE,0CAA0C;AAC1C,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,2FAA2F;AAC3F,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC;;;;GAIG;AACH,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC;4FAC4F;AAC5F,eAAO,MAAM,WAAW,SAAU,CAAC;AACnC,mFAAmF;AACnF,eAAO,MAAM,eAAe,OAAQ,CAAC;AACrC,qGAAqG;AACrG,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,OAAO,MAAM,CAAC;AAC3B,eAAO,MAAM,QAAQ,MAAM,CAAC;AAC5B,eAAO,MAAM,OAAO,YAAY,CAAC;AACjC,2EAA2E;AAC3E,eAAO,MAAM,QAAQ,qBAAqB,CAAC;AAC3C,eAAO,MAAM,cAAc,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {} from './presenter-controls.js';
|
|
2
|
+
/**
|
|
3
|
+
* Presenter tunables + option surface. Split out of presenter.ts so that file is just the controller
|
|
4
|
+
* under the size cap; these are pure declarations (interfaces + named constants), no behavior. None
|
|
5
|
+
* cross the browser↔bridge↔agent wire, so they live here, not in @reticlehq/core.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Border behavior.
|
|
9
|
+
* - 'session': base border persists connect→disconnect; the busy machine drives only the shimmer.
|
|
10
|
+
* - 'busy': back-compat — the busy machine toggles the base border on/off.
|
|
11
|
+
*/
|
|
12
|
+
export const BorderMode = { SESSION: 'session', BUSY: 'busy' };
|
|
13
|
+
export const DEFAULT_BORDER_MODE = BorderMode.SESSION;
|
|
14
|
+
export const DATA_BUSY = 'data-busy';
|
|
15
|
+
export const BUSY_ON = '1';
|
|
16
|
+
export const BUSY_OFF = '0';
|
|
17
|
+
export const DEFAULT_PACE = 450;
|
|
18
|
+
/**
|
|
19
|
+
* Glow state machine phases (exposed via glowPhase() for tests). A burst of activity flips the
|
|
20
|
+
* border IN once on the first activity, holds steady (the slow reticle-pulse breathing keeps running
|
|
21
|
+
* uninterrupted — no per-action restart/strobe), then fades OUT once after a quiet window.
|
|
22
|
+
*/
|
|
23
|
+
export const GlowPhase = {
|
|
24
|
+
IDLE: 'idle',
|
|
25
|
+
BUSY: 'busy',
|
|
26
|
+
FADING: 'fading',
|
|
27
|
+
};
|
|
28
|
+
/** Quiet window before busy -> fading. */
|
|
29
|
+
export const IDLE_AFTER_MS = 700;
|
|
30
|
+
/** Liveness heartbeat: how often the act strip refreshes its "idle · {duration}" clock. */
|
|
31
|
+
export const HEARTBEAT_MS = 1000;
|
|
32
|
+
/**
|
|
33
|
+
* After this much quiet, the act strip stops showing the last action and starts a LIVE, ticking
|
|
34
|
+
* "◌ idle · {duration} since last action" — so a watcher can tell a 3s think from a dead agent
|
|
35
|
+
* (the killer gap: a frozen panel used to look identical whether the agent paused or stopped).
|
|
36
|
+
*/
|
|
37
|
+
export const IDLE_NOTICE_MS = 4000;
|
|
38
|
+
/** Default session-idle-end: after this much quiet the session auto-ends (glow off, panel persists
|
|
39
|
+
* for analysis). Agent-tweakable via reticle_session { idleEndMs } for the app's needs. */
|
|
40
|
+
export const IDLE_END_MS = 300_000;
|
|
41
|
+
/** Floor for a tweaked idle-end so the agent can't set a uselessly tiny window. */
|
|
42
|
+
export const IDLE_END_MIN_MS = 5_000;
|
|
43
|
+
/** Must match the glow CSS opacity transition (.25s) so phase reaches idle after the fade paints. */
|
|
44
|
+
export const GLOW_FADE_MS = 250;
|
|
45
|
+
export const GLOW_ON = '1';
|
|
46
|
+
export const GLOW_OFF = '0';
|
|
47
|
+
export const DATA_ON = 'data-on';
|
|
48
|
+
/** Overlay-root attribute toggled when the panel is minimised to a bar. */
|
|
49
|
+
export const MIN_ATTR = 'data-reticle-min';
|
|
50
|
+
export const THROTTLED_ATTR = 'data-reticle-throttled';
|
|
51
|
+
//# sourceMappingURL=presenter-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presenter-config.js","sourceRoot":"","sources":["../../src/presenter/presenter-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,MAAM,yBAAyB,CAAC;AAE9D;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAW,CAAC;AAExE,MAAM,CAAC,MAAM,mBAAmB,GAAe,UAAU,CAAC,OAAO,CAAC;AAClE,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;AACrC,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,CAAC;AAC3B,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAiC5B,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAEhC;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;CACR,CAAC;AAGX,0CAA0C;AAC1C,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AACjC,2FAA2F;AAC3F,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AACnC;4FAC4F;AAC5F,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AACnC,mFAAmF;AACnF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AACrC,qGAAqG;AACrG,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAChC,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,CAAC;AAC3B,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,CAAC;AAC5B,MAAM,CAAC,MAAM,OAAO,GAAG,SAAS,CAAC;AACjC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,QAAQ,GAAG,kBAAkB,CAAC;AAC3C,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { HumanControlKind, PresenterTone, SessionState } from '@reticlehq/core';
|
|
2
|
+
/** data-reticle-state attribute on the overlay root; its value is always a SessionState. */
|
|
3
|
+
declare const DATA_RETICLE_STATE = "data-reticle-state";
|
|
4
|
+
/** Border fade-out delay after a session ends (native timer; presenter-only tunable). */
|
|
5
|
+
export declare const ENDED_FADE_MS = 4000;
|
|
6
|
+
/**
|
|
7
|
+
* One replayable flow as pushed to the panel. `start` is the first step's testid anchor — a page hint
|
|
8
|
+
* used to show a flow only where it can actually begin. Absent when the first step isn't testid-anchored.
|
|
9
|
+
*/
|
|
10
|
+
export interface FlowChip {
|
|
11
|
+
name: string;
|
|
12
|
+
start?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Payload the panel hands to its host when the human drives a control. */
|
|
15
|
+
export interface ControlIntent {
|
|
16
|
+
kind: HumanControlKind;
|
|
17
|
+
text?: string;
|
|
18
|
+
}
|
|
19
|
+
export type ControlHandler = (intent: ControlIntent) => void;
|
|
20
|
+
/** CSS for the control surface (injected with the rest of the presenter stylesheet). */
|
|
21
|
+
export declare const CONTROLS_CSS = "\n[data-reticle-hud] .reticle-ctl{pointer-events:auto;cursor:pointer;flex:none;display:inline-flex;align-items:center;justify-content:center;\n height:26px;padding:0 11px;border-radius:8px;border:1px solid var(--reticle-line);background:rgba(255,255,255,.04);\n color:var(--reticle-muted);font-family:var(--reticle-font);font-size:11px;font-weight:500;letter-spacing:.01em;line-height:1;\n transition:background .15s,color .15s,border-color .15s,transform .1s;}\n[data-reticle-hud] .reticle-ctl:hover{color:var(--reticle-fg);background:rgba(255,255,255,.09);}\n[data-reticle-hud] .reticle-ctl:active{transform:scale(.95);}\n[data-reticle-hud] .reticle-ctl:disabled{opacity:.35;cursor:default;}\n[data-reticle-hud] [data-reticle-end]{color:#ff9aa2;border-color:rgba(255,107,107,.22);}\n[data-reticle-hud] [data-reticle-end]:hover{color:#ff7a7a;border-color:rgba(255,107,107,.5);background:rgba(255,107,107,.1);}\n[data-reticle-hud] .reticle-badge{display:none;align-items:center;flex:none;font-weight:600;letter-spacing:.1em;font-size:9px;\n color:var(--reticle-accent);border:1px solid var(--reticle-accent);background:var(--reticle-accent-soft);padding:2px 8px;border-radius:999px;}\n[data-reticle-overlay][data-reticle-state=\"paused\"] [data-reticle-badge]{display:inline-flex;}\n[data-reticle-hud] [data-reticle-foot]{flex:none;padding:10px 12px 12px;border-top:1px solid var(--reticle-line2);background:rgba(0,0,0,.16);}\n[data-reticle-hud] .reticle-composer{display:flex;align-items:flex-end;gap:6px;background:rgba(255,255,255,.05);\n border:1px solid var(--reticle-line);border-radius:14px;padding:5px 6px 5px 14px;transition:border-color .15s,box-shadow .15s;}\n[data-reticle-hud] .reticle-composer:focus-within{border-color:var(--reticle-accent);box-shadow:0 0 0 3px var(--reticle-accent-soft);}\n[data-reticle-hud] .reticle-msg{flex:1;min-width:0;pointer-events:auto;background:transparent;border:none;outline:none;resize:none;\n color:var(--reticle-fg);font-family:var(--reticle-font);font-size:13px;line-height:18px;height:18px;min-height:18px;max-height:96px;\n padding:5px 0;overflow-y:auto;}\n[data-reticle-hud] .reticle-msg::placeholder{color:var(--reticle-faint);}\n[data-reticle-hud] .reticle-msg:disabled{opacity:.5;}\n[data-reticle-hud] .reticle-send{flex:none;width:30px;height:30px;padding:0;border-radius:10px;border:none;cursor:pointer;pointer-events:auto;\n background:var(--reticle-accent);color:#0b0d14;display:inline-flex;align-items:center;justify-content:center;transition:filter .15s,transform .1s;}\n[data-reticle-hud] .reticle-send svg{display:block;}\n[data-reticle-hud] .reticle-send:hover{filter:brightness(1.12);}\n[data-reticle-hud] .reticle-send:active{transform:scale(.9);}\n[data-reticle-hud] .reticle-send:disabled{opacity:.4;cursor:default;}\n[data-reticle-hud] .reticle-banner{display:none;flex:none;padding:8px 15px;color:var(--reticle-accent);\n font-size:11.5px;font-weight:500;border-bottom:1px solid var(--reticle-line2);background:var(--reticle-accent-soft);}\n[data-reticle-overlay][data-reticle-state=\"ended\"] [data-reticle-banner]{display:block;}\n/* Export row: hidden during a live session; revealed when ended so the run can be copied/saved. */\n[data-reticle-hud] .reticle-export{display:none;align-items:center;gap:8px;margin-top:9px;}\n[data-reticle-overlay][data-reticle-state=\"ended\"] [data-reticle-hud] .reticle-export{display:flex;}\n[data-reticle-hud] .reticle-export-msg{color:var(--reticle-ok);font-size:11px;opacity:0;transition:opacity .15s;}\n[data-reticle-hud] .reticle-export-msg[data-show=\"1\"]{opacity:1;}\n[data-reticle-overlay][data-reticle-state=\"paused\"] [data-reticle-glow][data-on=\"1\"]{animation:none;\n box-shadow:inset 0 0 0 3px rgba(246,180,76,.9),inset 0 0 30px 6px rgba(246,180,76,.4);}\n[data-reticle-overlay][data-reticle-state=\"ended\"] [data-reticle-glow][data-on=\"1\"]{animation:none;\n box-shadow:inset 0 0 0 2px rgba(61,215,166,.55);}\n/* Handoff tones tell the human the agent's mode at a glance. waiting = calm teal \"your turn\" (no\n alarm); ask = amber \"answer me\" with a pulse; warn = amber \"agent crashed\" with a pulse. Each leads\n the banner with an icon and overrides the calm ended-green accent. */\n[data-reticle-overlay][data-reticle-tone=\"waiting\"] [data-reticle-hud]{--reticle-accent:#38bdf8;--reticle-accent-soft:rgba(56,189,248,.16);}\n[data-reticle-overlay][data-reticle-tone=\"waiting\"] [data-reticle-banner]{font-weight:600;color:#7dd3fc;}\n[data-reticle-overlay][data-reticle-tone=\"waiting\"] [data-reticle-banner]::before{content:\"\\270B \";}\n[data-reticle-overlay][data-reticle-tone=\"waiting\"] [data-reticle-glow][data-on=\"1\"]{animation:none;\n box-shadow:inset 0 0 0 2px rgba(56,189,248,.5);}\n[data-reticle-overlay][data-reticle-tone=\"ask\"] [data-reticle-hud],\n[data-reticle-overlay][data-reticle-tone=\"warn\"] [data-reticle-hud]{--reticle-accent:#fb923c;--reticle-accent-soft:rgba(251,146,60,.18);}\n[data-reticle-overlay][data-reticle-tone=\"ask\"] [data-reticle-banner],\n[data-reticle-overlay][data-reticle-tone=\"warn\"] [data-reticle-banner]{font-weight:600;color:#fdba74;}\n[data-reticle-overlay][data-reticle-tone=\"ask\"] [data-reticle-banner]::before{content:\"\\2753 \";}\n[data-reticle-overlay][data-reticle-tone=\"warn\"] [data-reticle-banner]::before{content:\"\\26A0\\FE0F \";}\n[data-reticle-overlay][data-reticle-tone=\"ask\"] [data-reticle-glow][data-on=\"1\"],\n[data-reticle-overlay][data-reticle-tone=\"warn\"] [data-reticle-glow][data-on=\"1\"]{animation:reticle-warn-pulse 1.5s ease-in-out infinite;\n box-shadow:inset 0 0 0 2px rgba(251,146,60,.7);}\n@keyframes reticle-warn-pulse{0%,100%{box-shadow:inset 0 0 0 2px rgba(251,146,60,.32);}\n 50%{box-shadow:inset 0 0 0 3px rgba(251,146,60,.85),inset 0 0 26px 5px rgba(251,146,60,.34);}}\n/* Replay-a-flow row: the human re-runs a saved flow with no agent. Hidden until flows are pushed.\n Bounded + self-scrolling: it sits between the flex:1 log and the flex:none composer, so without a\n height cap a long flow list would squeeze the log to nothing and push the message input past the\n panel's overflow:hidden clip. flex:none + max-height + overflow-y keep the log and input always\n visible; extra flow chips scroll inside this section instead of growing the panel. */\n[data-reticle-hud] .reticle-flows{display:none;flex:none;flex-wrap:wrap;align-content:flex-start;gap:6px;\n padding:9px 12px;border-top:1px solid var(--reticle-line2);max-height:88px;overflow-y:auto;overscroll-behavior:contain;}\n[data-reticle-hud] .reticle-flows[data-has=\"1\"]{display:flex;}\n[data-reticle-hud] .reticle-flows::-webkit-scrollbar{width:9px;}\n[data-reticle-hud] .reticle-flows::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:9px;border:2px solid transparent;background-clip:content-box;}\n[data-reticle-hud] .reticle-flows-cap{flex:0 0 100%;margin-bottom:1px;color:var(--reticle-faint);font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;}\n[data-reticle-hud] .reticle-flow{pointer-events:auto;cursor:pointer;display:inline-flex;align-items:center;gap:5px;height:24px;padding:0 10px;\n border-radius:7px;border:1px solid var(--reticle-line);background:rgba(255,255,255,.04);color:var(--reticle-muted);\n font-family:var(--reticle-font);font-size:11px;font-weight:500;transition:background .15s,color .15s,border-color .15s,transform .1s;}\n[data-reticle-hud] .reticle-flow:hover{color:var(--reticle-fg);background:var(--reticle-accent-soft);border-color:var(--reticle-accent);}\n[data-reticle-hud] .reticle-flow:active{transform:scale(.95);}\n";
|
|
22
|
+
/** Header markup (controls + badge) injected into .reticle-hud-head, after the expand button. */
|
|
23
|
+
export declare const CONTROLS_HEAD_HTML: string;
|
|
24
|
+
/** Banner markup (between head and log, hidden unless ended). */
|
|
25
|
+
export declare const CONTROLS_BANNER_HTML = "<div data-reticle-banner class=\"reticle-banner\">Session ended</div>";
|
|
26
|
+
/** Replay-a-flow row (between log and footer); buttons are filled in by setFlows once flows arrive. */
|
|
27
|
+
export declare const CONTROLS_FLOWS_HTML = "<div data-reticle-flows class=\"reticle-flows\"><span class=\"reticle-flows-cap\">Replay a flow</span></div>";
|
|
28
|
+
/** Footer markup: a rounded composer pill (input + icon Send), appended after the log div. */
|
|
29
|
+
export declare const CONTROLS_FOOT_HTML: string;
|
|
30
|
+
/** Host hooks the panel needs from the Presenter (the control callback + activity-log appender). */
|
|
31
|
+
interface ControlPanelHost {
|
|
32
|
+
/** Emit a control to the host (onControl). The ONLY emit path — server pushes never call this. */
|
|
33
|
+
emit: (kind: HumanControlKind, text?: string) => void;
|
|
34
|
+
/** Append a local 🧑 row when the human sends a message. */
|
|
35
|
+
logHuman: (text: string) => void;
|
|
36
|
+
/** Injected ended-border fade delay (native timer). */
|
|
37
|
+
endedFadeMs: number;
|
|
38
|
+
/** The exported run state for the Copy/Export buttons (serialized to JSON). */
|
|
39
|
+
runState: () => unknown;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The live-control panel: owns the control element refs, the SessionState, the ended-fade timer,
|
|
43
|
+
* the DOM wiring, and the data-reticle-state visual machine. Split out of Presenter to keep both files
|
|
44
|
+
* under the 500-line cap. A click handler both emits a control AND optimistically applies state; the
|
|
45
|
+
* server's PRESENTER echo re-syncs via setState only (never emits) so a control is delivered once.
|
|
46
|
+
*/
|
|
47
|
+
export declare class ControlPanel {
|
|
48
|
+
#private;
|
|
49
|
+
constructor(host: ControlPanelHost);
|
|
50
|
+
get state(): SessionState;
|
|
51
|
+
/** Query control refs out of the mounted root and bind the DOM listeners, then paint active. */
|
|
52
|
+
mount(root: HTMLElement, glow: HTMLElement | undefined): void;
|
|
53
|
+
/** Clear any pending ended-fade timer (called from Presenter.destroy). */
|
|
54
|
+
teardown(): void;
|
|
55
|
+
/** Render the replayable-flow chips from the server push. Each ▶ click re-runs that flow, no agent.
|
|
56
|
+
* Takes the raw wire value and narrows it here (the panel is the consumer of this push). */
|
|
57
|
+
setFlows(flows: unknown): void;
|
|
58
|
+
/**
|
|
59
|
+
* Re-render the replay chips for the CURRENT page. A flow "starts here" iff its first step's anchor
|
|
60
|
+
* (a testid `start` hint) is present in the live DOM; flows with no start hint (signal/role-first,
|
|
61
|
+
* un-checkable) always show. Called on connect and on every route change so the list tracks the page —
|
|
62
|
+
* so you never see (or click) a flow that can't replay from where you are. Existing flows benefit
|
|
63
|
+
* without re-recording, since the hint is derived from the first step, not stored on the flow.
|
|
64
|
+
*/
|
|
65
|
+
refilterFlows(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Drive the panel's visual state. Idempotent; NEVER emits a control — the shared path for both the
|
|
68
|
+
* optimistic local click and the authoritative server PRESENTER echo. Only the ended-border fade
|
|
69
|
+
* touches a clock, via the injected native timer.
|
|
70
|
+
*/
|
|
71
|
+
setState(state: SessionState, text?: string, tone?: PresenterTone): void;
|
|
72
|
+
}
|
|
73
|
+
export { DATA_RETICLE_STATE };
|
|
74
|
+
//# sourceMappingURL=presenter-controls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presenter-controls.d.ts","sourceRoot":"","sources":["../../src/presenter/presenter-controls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAShF,4FAA4F;AAC5F,QAAA,MAAM,kBAAkB,uBAAuB,CAAC;AAsBhD,yFAAyF;AACzF,eAAO,MAAM,aAAa,OAAO,CAAC;AAElC;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;AAE7D,wFAAwF;AACxF,eAAO,MAAM,YAAY,y8OA2ExB,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,kBAAkB,QAAmQ,CAAC;AAEnS,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,0EAA+E,CAAC;AAEjH,uGAAuG;AACvG,eAAO,MAAM,mBAAmB,iHAA8G,CAAC;AAK/I,8FAA8F;AAC9F,eAAO,MAAM,kBAAkB,QAA6iB,CAAC;AA6B7kB,oGAAoG;AACpG,UAAU,gBAAgB;IACxB,kGAAkG;IAClG,IAAI,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,4DAA4D;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,OAAO,CAAC;CACzB;AAED;;;;;GAKG;AACH,qBAAa,YAAY;;gBAoBX,IAAI,EAAE,gBAAgB;IAIlC,IAAI,KAAK,IAAI,YAAY,CAExB;IAED,gGAAgG;IAChG,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,IAAI;IAwD7D,0EAA0E;IAC1E,QAAQ,IAAI,IAAI;IAwChB;iGAC6F;IAC7F,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAkB9B;;;;;;OAMG;IACH,aAAa,IAAI,IAAI;IAwBrB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI;CAuCzE;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|