@reticlehq/browser 2.13.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/actions-dom.d.ts +8 -20
- package/dist/actions/actions-dom.js +70 -69
- package/dist/actions/actions-press.d.ts +14 -0
- package/dist/actions/actions-press.js +123 -0
- package/dist/actions/actions.d.ts +1 -89
- package/dist/actions/actions.js +64 -365
- package/dist/actions/appeared-text.d.ts +0 -20
- package/dist/actions/appeared-text.js +6 -36
- package/dist/actions/danger-context.d.ts +3 -0
- package/dist/actions/danger-context.js +39 -0
- package/dist/actions/scroll.d.ts +8 -10
- package/dist/actions/scroll.js +28 -17
- package/dist/actions/synthetic/synthetic-input.d.ts +2 -0
- package/dist/actions/synthetic/synthetic-input.js +13 -0
- package/dist/actions/value-input.d.ts +0 -30
- package/dist/actions/value-input.js +0 -33
- package/dist/commands/commands.d.ts +0 -2
- package/dist/commands/commands.js +10 -70
- package/dist/connect-options.d.ts +2 -96
- package/dist/dom/a11y.d.ts +0 -29
- package/dist/dom/a11y.js +3 -90
- package/dist/dom/addressing/auto-anchor.d.ts +25 -0
- package/dist/dom/addressing/auto-anchor.js +41 -0
- package/dist/dom/addressing/refs.d.ts +14 -0
- package/dist/dom/addressing/refs.js +114 -0
- package/dist/dom/addressing/source.d.ts +9 -0
- package/dist/dom/addressing/source.js +29 -0
- package/dist/dom/chart.d.ts +0 -61
- package/dist/dom/chart.js +0 -60
- package/dist/dom/desktop-capture.d.ts +0 -30
- package/dist/dom/desktop-capture.js +1 -73
- package/dist/dom/dom-ignore.d.ts +0 -30
- package/dist/dom/dom-ignore.js +1 -48
- package/dist/dom/occlusion.d.ts +0 -7
- package/dist/dom/occlusion.js +31 -12
- package/dist/dom/paint-context.d.ts +6 -0
- package/dist/dom/paint-context.js +38 -0
- package/dist/dom/query.d.ts +0 -14
- package/dist/dom/query.js +50 -216
- package/dist/dom/realm.d.ts +0 -20
- package/dist/dom/realm.js +0 -28
- package/dist/dom/shadow-registry.d.ts +0 -33
- package/dist/dom/shadow-registry.js +2 -72
- package/dist/dom/snapshot.d.ts +2 -43
- package/dist/dom/snapshot.js +27 -152
- package/dist/dom/theme.d.ts +0 -37
- package/dist/dom/theme.js +2 -52
- package/dist/dom/virtualized.d.ts +0 -17
- package/dist/dom/virtualized.js +0 -27
- package/dist/edit-epoch.d.ts +1 -23
- package/dist/edit-epoch.js +1 -53
- package/dist/index.d.ts +4 -5
- package/dist/index.js +4 -28
- package/dist/observers/animation.d.ts +0 -1
- package/dist/observers/animation.js +1 -4
- package/dist/observers/blind-spots.d.ts +0 -26
- package/dist/observers/blind-spots.js +3 -62
- package/dist/observers/console.d.ts +1 -2
- package/dist/observers/console.js +41 -30
- package/dist/observers/context-open.d.ts +1 -11
- package/dist/observers/context-open.js +10 -14
- package/dist/observers/departure.d.ts +3 -0
- package/dist/observers/departure.js +52 -0
- package/dist/observers/dialogs.d.ts +2 -0
- package/dist/observers/dialogs.js +39 -0
- package/dist/observers/dom.js +28 -52
- package/dist/observers/download.d.ts +1 -2
- package/dist/observers/download.js +39 -56
- package/dist/observers/focus.d.ts +0 -6
- package/dist/observers/focus.js +0 -7
- package/dist/observers/frames.d.ts +0 -9
- package/dist/observers/frames.js +1 -28
- package/dist/observers/health.d.ts +0 -5
- package/dist/observers/health.js +2 -34
- package/dist/observers/install-all.d.ts +2 -0
- package/dist/observers/install-all.js +26 -27
- package/dist/observers/ipc.d.ts +0 -25
- package/dist/observers/ipc.js +0 -65
- package/dist/observers/navigation.d.ts +2 -0
- package/dist/observers/navigation.js +33 -0
- package/dist/observers/net-detail/network-body.d.ts +12 -0
- package/dist/observers/net-detail/network-body.js +71 -0
- package/dist/observers/net-detail/network-redact.d.ts +1 -0
- package/dist/observers/net-detail/network-redact.js +1 -0
- package/dist/observers/network-stream.d.ts +0 -21
- package/dist/observers/network-stream.js +3 -46
- package/dist/observers/network.d.ts +3 -27
- package/dist/observers/network.js +178 -295
- package/dist/observers/perf.d.ts +0 -10
- package/dist/observers/perf.js +0 -16
- package/dist/observers/route.d.ts +1 -2
- package/dist/observers/route.js +13 -19
- package/dist/observers/scroll.d.ts +0 -1
- package/dist/observers/scroll.js +2 -11
- package/dist/observers/sdk-failure.d.ts +1 -9
- package/dist/observers/sdk-failure.js +1 -30
- package/dist/observers/state.d.ts +1 -11
- package/dist/observers/state.js +13 -41
- package/dist/observers/storage.d.ts +0 -14
- package/dist/observers/storage.js +10 -34
- package/dist/observers/types.d.ts +0 -15
- package/dist/observers/types.js +0 -14
- package/dist/patching/capture-method.d.ts +0 -24
- package/dist/patching/capture-method.js +0 -26
- package/dist/presenter/chrome/layers.d.ts +2 -0
- package/dist/presenter/chrome/layers.js +2 -0
- package/dist/presenter/chrome/log-kinds.d.ts +12 -0
- package/dist/presenter/chrome/log-kinds.js +7 -0
- package/dist/presenter/{overlay.d.ts → chrome/overlay.d.ts} +0 -1
- package/dist/presenter/{overlay.js → chrome/overlay.js} +0 -1
- package/dist/presenter/chrome/presenter-brand.d.ts +3 -0
- package/dist/presenter/{presenter-brand.js → chrome/presenter-brand.js} +0 -21
- package/dist/presenter/chrome/presenter-effects.d.ts +4 -0
- package/dist/presenter/{presenter-effects.js → chrome/presenter-effects.js} +1 -10
- package/dist/presenter/chrome/presenter-hud-chrome.d.ts +7 -0
- package/dist/presenter/{presenter-hud-chrome.js → chrome/presenter-hud-chrome.js} +0 -10
- package/dist/presenter/chrome/presenter-log.d.ts +17 -0
- package/dist/presenter/{presenter-log.js → chrome/presenter-log.js} +5 -54
- package/dist/presenter/chrome/presenter-report-copy.d.ts +51 -0
- package/dist/presenter/chrome/presenter-report-copy.js +95 -0
- package/dist/presenter/chrome/presenter-safe-html.d.ts +2 -0
- package/dist/presenter/chrome/presenter-safe-html.js +16 -0
- package/dist/presenter/{presenter-tally.d.ts → chrome/presenter-tally.d.ts} +0 -5
- package/dist/presenter/{presenter-tally.js → chrome/presenter-tally.js} +1 -5
- package/dist/presenter/{presenter-verbs.js → chrome/presenter-verbs.js} +0 -7
- package/dist/presenter/{presenter-heroicons-data.d.ts → icons/presenter-heroicons-data.d.ts} +1 -8
- package/dist/presenter/{presenter-heroicons-data.js → icons/presenter-heroicons-data.js} +1 -8
- package/dist/presenter/{presenter-icons.d.ts → icons/presenter-icons.d.ts} +1 -6
- package/dist/presenter/{presenter-icons.js → icons/presenter-icons.js} +1 -6
- package/dist/presenter/presenter-account-styles.d.ts +1 -0
- package/dist/presenter/presenter-account-styles.js +99 -0
- package/dist/presenter/presenter-account.d.ts +40 -0
- package/dist/presenter/presenter-account.js +178 -0
- package/dist/presenter/presenter-config.d.ts +10 -107
- package/dist/presenter/presenter-config.js +5 -92
- package/dist/presenter/presenter-controls.d.ts +1 -35
- package/dist/presenter/presenter-controls.js +10 -133
- package/dist/presenter/presenter-dock-layout.d.ts +0 -3
- package/dist/presenter/presenter-dock-layout.js +1 -5
- package/dist/presenter/presenter-drag.d.ts +2 -42
- package/dist/presenter/presenter-drag.js +3 -76
- package/dist/presenter/presenter-glow.d.ts +0 -21
- package/dist/presenter/presenter-glow.js +2 -28
- package/dist/presenter/presenter-hud-position.d.ts +18 -0
- package/dist/presenter/presenter-hud-position.js +50 -0
- package/dist/presenter/presenter-report-styles.d.ts +0 -6
- package/dist/presenter/presenter-report-styles.js +22 -7
- package/dist/presenter/presenter-report.d.ts +5 -7
- package/dist/presenter/presenter-report.js +44 -95
- package/dist/presenter/presenter-run-state.d.ts +1 -8
- package/dist/presenter/presenter-run-state.js +1 -6
- package/dist/presenter/presenter-settings-styles.d.ts +0 -1
- package/dist/presenter/presenter-settings-styles.js +2 -2
- package/dist/presenter/presenter-settings.d.ts +5 -23
- package/dist/presenter/presenter-settings.js +21 -33
- package/dist/presenter/presenter-shell-styles.js +23 -20
- package/dist/presenter/presenter-shell.d.ts +6 -18
- package/dist/presenter/presenter-shell.js +26 -77
- package/dist/presenter/presenter-styles.d.ts +2 -10
- package/dist/presenter/presenter-styles.js +6 -12
- package/dist/presenter/presenter-workspace.d.ts +4 -4
- package/dist/presenter/presenter-workspace.js +30 -10
- package/dist/presenter/presenter.d.ts +3 -63
- package/dist/presenter/presenter.js +29 -132
- package/dist/presenter/tour/tour-view.d.ts +33 -0
- package/dist/presenter/tour/tour-view.js +188 -0
- package/dist/presenter/tour/tour.d.ts +25 -0
- package/dist/presenter/tour/tour.js +245 -0
- package/dist/recorder/recorder-styles.d.ts +0 -6
- package/dist/recorder/recorder-styles.js +0 -6
- package/dist/recorder/recorder.d.ts +0 -34
- package/dist/recorder/recorder.js +6 -49
- package/dist/registry/auto-testids.d.ts +0 -19
- package/dist/registry/auto-testids.js +1 -21
- package/dist/registry/capabilities.d.ts +0 -31
- package/dist/registry/capabilities.js +1 -46
- package/dist/registry/commit-and-signal.d.ts +0 -6
- package/dist/registry/commit-and-signal.js +1 -7
- package/dist/registry/declared-channels.d.ts +2 -0
- package/dist/registry/declared-channels.js +14 -0
- package/dist/registry/declared-platform.d.ts +4 -0
- package/dist/registry/declared-platform.js +34 -0
- package/dist/registry/domains.d.ts +0 -8
- package/dist/registry/domains.js +0 -7
- package/dist/registry/emitter.d.ts +0 -14
- package/dist/registry/emitter.js +1 -11
- package/dist/registry/store-adapters.d.ts +0 -186
- package/dist/registry/store-adapters.js +1 -164
- package/dist/registry/{adapters.d.ts → stores/adapters.d.ts} +0 -10
- package/dist/registry/{adapters.js → stores/adapters.js} +0 -10
- package/dist/registry/stores.d.ts +0 -33
- package/dist/registry/stores.js +1 -60
- package/dist/reticle-presenter-helpers.d.ts +0 -13
- package/dist/reticle-presenter-helpers.js +10 -20
- package/dist/reticle-singleton.d.ts +2 -0
- package/dist/reticle-singleton.js +3 -0
- package/dist/reticle.d.ts +1 -52
- package/dist/reticle.js +115 -180
- package/dist/review/annotator-styles.js +1 -8
- package/dist/review/annotator.d.ts +2 -13
- package/dist/review/annotator.js +2 -42
- package/dist/review/mark-anchor.d.ts +0 -11
- package/dist/review/mark-anchor.js +3 -11
- package/dist/security/serialization.d.ts +0 -20
- package/dist/security/serialization.js +1 -66
- package/dist/session-continuity.d.ts +0 -16
- package/dist/session-continuity.js +1 -20
- package/dist/timers/clock.d.ts +1 -14
- package/dist/timers/clock.js +59 -60
- package/dist/timers/console/native-console.js +5 -0
- package/dist/timers/native/native-timers.d.ts +11 -0
- package/dist/timers/native/native-timers.js +48 -0
- package/dist/transport/transport.d.ts +0 -51
- package/dist/transport/transport.js +5 -131
- package/dist/transport/unreachable-message.d.ts +0 -17
- package/dist/transport/unreachable-message.js +0 -17
- package/dist/util/captured-method.d.ts +0 -35
- package/dist/util/captured-method.js +0 -35
- package/package.json +5 -4
- package/dist/actions/synthetic-input.d.ts +0 -9
- package/dist/actions/synthetic-input.js +0 -40
- package/dist/dom/auto-anchor.d.ts +0 -65
- package/dist/dom/auto-anchor.js +0 -74
- package/dist/dom/refs.d.ts +0 -90
- package/dist/dom/refs.js +0 -245
- package/dist/dom/source.d.ts +0 -53
- package/dist/dom/source.js +0 -74
- package/dist/observers/network-body.d.ts +0 -35
- package/dist/observers/network-body.js +0 -168
- package/dist/observers/network-redact.d.ts +0 -20
- package/dist/observers/network-redact.js +0 -80
- package/dist/presenter/presenter-brand.d.ts +0 -22
- package/dist/presenter/presenter-effects.d.ts +0 -13
- package/dist/presenter/presenter-hud-chrome.d.ts +0 -17
- package/dist/presenter/presenter-log.d.ts +0 -64
- package/dist/presenter/presenter-report-copy.d.ts +0 -112
- package/dist/presenter/presenter-report-copy.js +0 -156
- package/dist/presenter/presenter-test-helpers.d.ts +0 -16
- package/dist/presenter/presenter-test-helpers.js +0 -41
- package/dist/timers/native-console.js +0 -9
- package/dist/timers/native-timers.d.ts +0 -36
- package/dist/timers/native-timers.js +0 -78
- /package/dist/presenter/{presenter-verbs.d.ts → chrome/presenter-verbs.d.ts} +0 -0
- /package/dist/timers/{native-console.d.ts → console/native-console.d.ts} +0 -0
package/dist/dom/source.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where an element is defined in the codebase.
|
|
3
|
-
*
|
|
4
|
-
* This is the single most valuable thing Reticle can hand an agent that has to fix what Reticle just
|
|
5
|
-
* found. Locating the right FILE is what turns a report into an edit; without it the agent pays for a
|
|
6
|
-
* search loop that the instrumentation already knows the answer to.
|
|
7
|
-
*
|
|
8
|
-
* Two lookups, because the callers have very different cost budgets:
|
|
9
|
-
*
|
|
10
|
-
* sourceFromDom — reads the babel-stamped `data-reticle-source` off the nearest ancestor. One
|
|
11
|
-
* native upward walk, bounded by tree depth. Safe to call per element on paths
|
|
12
|
-
* that describe many elements at once (query results, snapshots).
|
|
13
|
-
* sourceFor — prefers a framework adapter's answer (which knows the component that RENDERED
|
|
14
|
-
* the element, not just the nearest stamped host) and falls back to the DOM. The
|
|
15
|
-
* adapter path walks the fiber tree, so this belongs on single-element paths
|
|
16
|
-
* (inspect, act, review) and not in a loop.
|
|
17
|
-
*
|
|
18
|
-
* Both report source independently of how the element is ANCHORED. Anchor answers "how do I find this
|
|
19
|
-
* again", source answers "where is it written" — collapsing the two once meant that adding a
|
|
20
|
-
* data-testid, which Reticle's own docs recommend, silently removed the source pointer.
|
|
21
|
-
*/
|
|
22
|
-
export interface SourceLocation {
|
|
23
|
-
file: string;
|
|
24
|
-
line: number;
|
|
25
|
-
}
|
|
26
|
-
/** Parse a `data-reticle-source="file:line:column"` value into `{ file, line }` (column dropped). */
|
|
27
|
-
export declare function parseSourceAttr(value: string | null): SourceLocation | undefined;
|
|
28
|
-
/** The nearest babel-stamped source at or above this element. Cheap enough to call in bulk. */
|
|
29
|
-
export declare function sourceFromDom(el: Element): SourceLocation | undefined;
|
|
30
|
-
/** Best source for the element: the framework adapter's, else the nearest babel-stamped attribute. */
|
|
31
|
-
export declare function sourceFor(el: Element, adapterSource: SourceLocation | undefined): SourceLocation | undefined;
|
|
32
|
-
/**
|
|
33
|
-
* Does ANY element in this document carry a source stamp?
|
|
34
|
-
*
|
|
35
|
-
* The difference between "this element has no stamp" and "the stamping loader is not running at
|
|
36
|
-
* all" — two answers that look identical from a single missing `source` field, and that call for
|
|
37
|
-
* completely different next actions. The first is ordinary: not every element sits under a stamped
|
|
38
|
-
* host. The second means "fix at file:line", the single most-cited reason to reach for Reticle over
|
|
39
|
-
* a generic DOM tool, is silently unavailable for the whole session — and it has been discovered by
|
|
40
|
-
* reading the adapter's source rather than from anything Reticle said.
|
|
41
|
-
*
|
|
42
|
-
* One `querySelector`, which stops at the first hit, so this is cheap enough to answer on a
|
|
43
|
-
* single-element path like inspect. It is only consulted when a source is already missing.
|
|
44
|
-
*/
|
|
45
|
-
export declare function documentHasSourceStamps(doc: Document): boolean;
|
|
46
|
-
/**
|
|
47
|
-
* `file:line` — the form an agent can act on directly.
|
|
48
|
-
*
|
|
49
|
-
* Deliberately a single compact string rather than an object: it costs a couple of dozen bytes on a
|
|
50
|
-
* descriptor that may repeat hundreds of times in one response, and every consumer of it is either
|
|
51
|
-
* opening an editor or printing it.
|
|
52
|
-
*/
|
|
53
|
-
export declare function formatSource(source: SourceLocation | undefined): string | undefined;
|
package/dist/dom/source.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where an element is defined in the codebase.
|
|
3
|
-
*
|
|
4
|
-
* This is the single most valuable thing Reticle can hand an agent that has to fix what Reticle just
|
|
5
|
-
* found. Locating the right FILE is what turns a report into an edit; without it the agent pays for a
|
|
6
|
-
* search loop that the instrumentation already knows the answer to.
|
|
7
|
-
*
|
|
8
|
-
* Two lookups, because the callers have very different cost budgets:
|
|
9
|
-
*
|
|
10
|
-
* sourceFromDom — reads the babel-stamped `data-reticle-source` off the nearest ancestor. One
|
|
11
|
-
* native upward walk, bounded by tree depth. Safe to call per element on paths
|
|
12
|
-
* that describe many elements at once (query results, snapshots).
|
|
13
|
-
* sourceFor — prefers a framework adapter's answer (which knows the component that RENDERED
|
|
14
|
-
* the element, not just the nearest stamped host) and falls back to the DOM. The
|
|
15
|
-
* adapter path walks the fiber tree, so this belongs on single-element paths
|
|
16
|
-
* (inspect, act, review) and not in a loop.
|
|
17
|
-
*
|
|
18
|
-
* Both report source independently of how the element is ANCHORED. Anchor answers "how do I find this
|
|
19
|
-
* again", source answers "where is it written" — collapsing the two once meant that adding a
|
|
20
|
-
* data-testid, which Reticle's own docs recommend, silently removed the source pointer.
|
|
21
|
-
*/
|
|
22
|
-
import { DATA_RETICLE_SOURCE_ATTR } from '@reticlehq/core';
|
|
23
|
-
/** Stamped by @reticlehq/babel-plugin / @reticlehq/vite-plugin in dev as `file:line:column`. */
|
|
24
|
-
const SOURCE_ATTR = DATA_RETICLE_SOURCE_ATTR;
|
|
25
|
-
/** Parse a `data-reticle-source="file:line:column"` value into `{ file, line }` (column dropped). */
|
|
26
|
-
export function parseSourceAttr(value) {
|
|
27
|
-
if (null === value)
|
|
28
|
-
return undefined;
|
|
29
|
-
const m = /^(.*):(\d+):(\d+)$/.exec(value);
|
|
30
|
-
if (null === m)
|
|
31
|
-
return undefined;
|
|
32
|
-
const file = m[1];
|
|
33
|
-
const line = Number(m[2]);
|
|
34
|
-
if (file === undefined || 0 === file.length || !Number.isFinite(line))
|
|
35
|
-
return undefined;
|
|
36
|
-
return { file, line };
|
|
37
|
-
}
|
|
38
|
-
/** The nearest babel-stamped source at or above this element. Cheap enough to call in bulk. */
|
|
39
|
-
export function sourceFromDom(el) {
|
|
40
|
-
const host = el.closest(`[${SOURCE_ATTR}]`);
|
|
41
|
-
return host !== null ? parseSourceAttr(host.getAttribute(SOURCE_ATTR)) : undefined;
|
|
42
|
-
}
|
|
43
|
-
/** Best source for the element: the framework adapter's, else the nearest babel-stamped attribute. */
|
|
44
|
-
export function sourceFor(el, adapterSource) {
|
|
45
|
-
if (adapterSource !== undefined)
|
|
46
|
-
return { file: adapterSource.file, line: adapterSource.line };
|
|
47
|
-
return sourceFromDom(el);
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Does ANY element in this document carry a source stamp?
|
|
51
|
-
*
|
|
52
|
-
* The difference between "this element has no stamp" and "the stamping loader is not running at
|
|
53
|
-
* all" — two answers that look identical from a single missing `source` field, and that call for
|
|
54
|
-
* completely different next actions. The first is ordinary: not every element sits under a stamped
|
|
55
|
-
* host. The second means "fix at file:line", the single most-cited reason to reach for Reticle over
|
|
56
|
-
* a generic DOM tool, is silently unavailable for the whole session — and it has been discovered by
|
|
57
|
-
* reading the adapter's source rather than from anything Reticle said.
|
|
58
|
-
*
|
|
59
|
-
* One `querySelector`, which stops at the first hit, so this is cheap enough to answer on a
|
|
60
|
-
* single-element path like inspect. It is only consulted when a source is already missing.
|
|
61
|
-
*/
|
|
62
|
-
export function documentHasSourceStamps(doc) {
|
|
63
|
-
return doc.querySelector(`[${SOURCE_ATTR}]`) !== null;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* `file:line` — the form an agent can act on directly.
|
|
67
|
-
*
|
|
68
|
-
* Deliberately a single compact string rather than an object: it costs a couple of dozen bytes on a
|
|
69
|
-
* descriptor that may repeat hundreds of times in one response, and every consumer of it is either
|
|
70
|
-
* opening an editor or printing it.
|
|
71
|
-
*/
|
|
72
|
-
export function formatSource(source) {
|
|
73
|
-
return source === undefined ? undefined : `${source.file}:${String(source.line)}`;
|
|
74
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Is this response body still arriving after the request itself resolved?
|
|
3
|
-
*
|
|
4
|
-
* STRUCTURAL, not a content-type allowlist. The first version listed `x-component|x-ndjson|
|
|
5
|
-
* application/stream` — which is to say "Next.js RSC, plus two guesses". It closed the exact defect
|
|
6
|
-
* it was written against and left every other streamed response as invisible as before: a chunked
|
|
7
|
-
* `application/json` from a token API, a streamed HTML document, an export assembled server-side.
|
|
8
|
-
* Fixing one app's symptom and calling the class solved is how a false green comes back wearing
|
|
9
|
-
* different clothes.
|
|
10
|
-
*
|
|
11
|
-
* The real signal is on the wire: a response with a BODY and no `content-length` is being sent
|
|
12
|
-
* chunked, which is the definition of "the server is still writing". `content-length` present means
|
|
13
|
-
* the size was known up front and the body cannot grow.
|
|
14
|
-
*
|
|
15
|
-
* Deliberately independent of content type, with one exception above for streams that never end.
|
|
16
|
-
*/
|
|
17
|
-
export declare function isStreamingBody(contentType: string | null, contentLength: string | null): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Resolve with the body text, or `undefined` if it takes too long.
|
|
20
|
-
*
|
|
21
|
-
* The app is already awaiting our patched fetch, so any unbounded read here is a hang in the host app.
|
|
22
|
-
* Losing an observation is always preferable to freezing the page being observed.
|
|
23
|
-
*/
|
|
24
|
-
export declare function withBodyDeadline(read: Promise<string>): Promise<string | undefined>;
|
|
25
|
-
export declare function isCapturableType(contentType: string | null): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Redact + cap a body for the agent transcript. JSON is parsed and run through the same
|
|
28
|
-
* sanitizeForTransport redaction used for state (sensitive keys -> [REDACTED]); every other text body
|
|
29
|
-
* (and JSON that didn't parse) goes through redactText so form/plain-text credentials can't leak.
|
|
30
|
-
* Returns the (possibly truncated) body plus whether it was cut.
|
|
31
|
-
*/
|
|
32
|
-
export declare function projectBody(rawText: string, contentType: string | null): {
|
|
33
|
-
body: string;
|
|
34
|
-
truncated: boolean;
|
|
35
|
-
};
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Response/request BODY projection for the network observer.
|
|
3
|
-
*
|
|
4
|
-
* Split out of network.ts, which had grown to hold URL redaction, body projection, fetch, XHR, SSE,
|
|
5
|
-
* WebSocket and sendBeacon at once. This module owns exactly one question: given a body, what is safe
|
|
6
|
-
* and affordable to report?
|
|
7
|
-
*/
|
|
8
|
-
import { REDACTED_VALUE } from '@reticlehq/core';
|
|
9
|
-
import { isSensitiveKey, safeStringify, scrubKnownSecrets } from '../security/serialization.js';
|
|
10
|
-
import { nativeClearTimeout, nativeSetTimeout } from '../timers/native-timers.js';
|
|
11
|
-
/** Only text-like bodies are worth capturing; binary (images/fonts/octet-stream) is skipped. */
|
|
12
|
-
const CAPTURABLE_CONTENT = /application\/json|text\/|application\/xml|x-www-form-urlencoded|graphql/i;
|
|
13
|
-
/**
|
|
14
|
-
* Content types that are STREAMS, never complete bodies.
|
|
15
|
-
*
|
|
16
|
-
* `text/event-stream` matches `text/` in CAPTURABLE_CONTENT, and body capture awaited
|
|
17
|
-
* `res.clone.text` BEFORE returning the response to the app. A clone of a stream only settles when
|
|
18
|
-
* the stream ends — and an SSE stream does not end — so the app's `await fetch...)` never resolved.
|
|
19
|
-
* Enabling body capture silently hung every streaming endpoint (SSE, and the chunked `application/json`
|
|
20
|
-
* every token-streaming model API uses), leaving a permanently loading UI with no reason to suspect the
|
|
21
|
-
* observability SDK. Never read these; the frame observer covers SSE properly.
|
|
22
|
-
*/
|
|
23
|
-
const STREAMING_CONTENT = /event-stream|x-ndjson|application\/stream/i;
|
|
24
|
-
/**
|
|
25
|
-
* Content types that stay OPEN by design — watching them would make every first settle pay the full
|
|
26
|
-
* watch bound for a stream doing exactly its job. Real SSE is covered by the EventSource observer.
|
|
27
|
-
*/
|
|
28
|
-
const ENDLESS_BY_DESIGN = /event-stream/i;
|
|
29
|
-
/**
|
|
30
|
-
* Is this response body still arriving after the request itself resolved?
|
|
31
|
-
*
|
|
32
|
-
* STRUCTURAL, not a content-type allowlist. The first version listed `x-component|x-ndjson|
|
|
33
|
-
* application/stream` — which is to say "Next.js RSC, plus two guesses". It closed the exact defect
|
|
34
|
-
* it was written against and left every other streamed response as invisible as before: a chunked
|
|
35
|
-
* `application/json` from a token API, a streamed HTML document, an export assembled server-side.
|
|
36
|
-
* Fixing one app's symptom and calling the class solved is how a false green comes back wearing
|
|
37
|
-
* different clothes.
|
|
38
|
-
*
|
|
39
|
-
* The real signal is on the wire: a response with a BODY and no `content-length` is being sent
|
|
40
|
-
* chunked, which is the definition of "the server is still writing". `content-length` present means
|
|
41
|
-
* the size was known up front and the body cannot grow.
|
|
42
|
-
*
|
|
43
|
-
* Deliberately independent of content type, with one exception above for streams that never end.
|
|
44
|
-
*/
|
|
45
|
-
export function isStreamingBody(contentType, contentLength) {
|
|
46
|
-
if (contentType !== null && ENDLESS_BY_DESIGN.test(contentType))
|
|
47
|
-
return false;
|
|
48
|
-
return null === contentLength;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Longest the SDK will wait on a response-body clone before emitting without it.
|
|
52
|
-
*
|
|
53
|
-
* Two layers protect the app. `text/event-stream` and friends are skipped outright, which covers the
|
|
54
|
-
* common streaming case at zero cost. This deadline is the backstop for a body that streams WITHOUT
|
|
55
|
-
* announcing it in its content type — chunked `application/json` from a token-streaming API. Gating on
|
|
56
|
-
* `content-length` instead was tried and rejected: plenty of complete responses omit it (gzip, HTTP/2),
|
|
57
|
-
* so that would silently stop capturing bodies for ordinary apps. A bounded half-second on a rare path
|
|
58
|
-
* beats an unbounded hang, and beats losing capture everywhere.
|
|
59
|
-
*/
|
|
60
|
-
const BODY_READ_TIMEOUT_MS = 500;
|
|
61
|
-
/**
|
|
62
|
-
* Resolve with the body text, or `undefined` if it takes too long.
|
|
63
|
-
*
|
|
64
|
-
* The app is already awaiting our patched fetch, so any unbounded read here is a hang in the host app.
|
|
65
|
-
* Losing an observation is always preferable to freezing the page being observed.
|
|
66
|
-
*/
|
|
67
|
-
export async function withBodyDeadline(read) {
|
|
68
|
-
// The timer is CLEARED on the winning path. Left uncleared, every captured body leaves a live timer
|
|
69
|
-
// and a retained closure behind — harmless individually, but `boundedFrame` in this same package
|
|
70
|
-
// already races-with-cleanup correctly, so not reusing that shape was an oversight rather than a
|
|
71
|
-
// choice. It also keeps test workers from being held open by pending handles.
|
|
72
|
-
let timer;
|
|
73
|
-
try {
|
|
74
|
-
return await Promise.race([
|
|
75
|
-
read,
|
|
76
|
-
new Promise((resolve) => {
|
|
77
|
-
timer = nativeSetTimeout(() => resolve(undefined), BODY_READ_TIMEOUT_MS);
|
|
78
|
-
}),
|
|
79
|
-
]);
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
if (timer !== undefined)
|
|
83
|
-
nativeClearTimeout(timer);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
export function isCapturableType(contentType) {
|
|
87
|
-
if (null === contentType)
|
|
88
|
-
return false;
|
|
89
|
-
if (STREAMING_CONTENT.test(contentType))
|
|
90
|
-
return false;
|
|
91
|
-
return CAPTURABLE_CONTENT.test(contentType);
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Per-body character cap. Bodies ride the same ring buffer as the DOM/route/console timeline, so an
|
|
95
|
-
* uncapped body could evict the whole behavioral history; the small cap keeps a few large responses
|
|
96
|
-
* from starving the timeline (the separate-budget concern in the scalability audit).
|
|
97
|
-
*/
|
|
98
|
-
const MAX_BODY_CHARS = 8192;
|
|
99
|
-
/**
|
|
100
|
-
* Hard bound on how much of a body is ever PARSED or SCANNED, independent of how much is reported.
|
|
101
|
-
*
|
|
102
|
-
* Only twice the output cap, and that ceiling is measured rather than guessed. The redaction pass uses
|
|
103
|
-
* `[A-Za-z0-9_.-]+` followed by a delimiter, which backtracks quadratically on a long run without one.
|
|
104
|
-
* Timed on this machine: 8 KB → 36 ms, 16 KB → 136 ms, 64 KB → 2067 ms. A first attempt at 8× the
|
|
105
|
-
* output cap therefore still froze the main thread for seconds, so the bound is set where the cost
|
|
106
|
-
* stays bounded AND redaction keeps enough context to catch a secret straddling the reported edge.
|
|
107
|
-
* Scanning far past the output cap is wasted work in any case — only 8 KB is ever reported.
|
|
108
|
-
*/
|
|
109
|
-
const MAX_BODY_SCAN_CHARS = MAX_BODY_CHARS * 2;
|
|
110
|
-
/**
|
|
111
|
-
* An `Authorization: Bearer …` / `Basic …` credential. The token side requires credential shape — 16+
|
|
112
|
-
* chars AND at least one digit or symbol — so ordinary prose ("Basic subscription includes…", "Bearer
|
|
113
|
-
* capacity exceeded") is NOT mangled, only actual opaque tokens are.
|
|
114
|
-
*/
|
|
115
|
-
const AUTH_SCHEME_TOKEN = /\b(Bearer|Basic)\s+(?=[A-Za-z0-9._~+/=-]{16,})(?=[A-Za-z0-9._~+/=-]*[\d._~+/=-])[A-Za-z0-9._~+/=-]+/gi;
|
|
116
|
-
/**
|
|
117
|
-
* Redact credentials in ANY text body (form-urlencoded, text/plain, xml, or JSON that failed to parse).
|
|
118
|
-
* sanitizeForTransport only redacts KEYS inside a parsed object, so a `password=secret` form post or a
|
|
119
|
-
* `Bearer <token>` string would otherwise ship verbatim. Redacts the value of any `key=value` / `key: value`
|
|
120
|
-
* pair whose key is sensitive, plus credential-shaped auth-scheme tokens.
|
|
121
|
-
*/
|
|
122
|
-
function redactText(text) {
|
|
123
|
-
return (text
|
|
124
|
-
// Auth-scheme tokens FIRST: `Authorization: Bearer <token>` — the key/value rule below would
|
|
125
|
-
// otherwise consume just "Bearer" as Authorization's value (it stops at whitespace) and leave the
|
|
126
|
-
// token behind, so the scheme rule must run before it.
|
|
127
|
-
.replace(AUTH_SCHEME_TOKEN, (_m, scheme) => `${scheme} ${REDACTED_VALUE}`)
|
|
128
|
-
.replace(/([A-Za-z0-9_.-]+)(\s*[=:]\s*"?)([^&\s,;"}]+)/g, (match, key, sep) => isSensitiveKey(key) ? `${key}${sep}${REDACTED_VALUE}` : match));
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Redact + cap a body for the agent transcript. JSON is parsed and run through the same
|
|
132
|
-
* sanitizeForTransport redaction used for state (sensitive keys -> [REDACTED]); every other text body
|
|
133
|
-
* (and JSON that didn't parse) goes through redactText so form/plain-text credentials can't leak.
|
|
134
|
-
* Returns the (possibly truncated) body plus whether it was cut.
|
|
135
|
-
*/
|
|
136
|
-
export function projectBody(rawText, contentType) {
|
|
137
|
-
// Bound the INPUT before any parsing or scanning. The cap used to be applied only at the end, so a
|
|
138
|
-
// large body was JSON.parsed in full, deep-walked, re-stringified, and swept by two global regexes
|
|
139
|
-
// before all but 8 KB of the result was thrown away — seconds of synchronous main-thread work for a
|
|
140
|
-
// fixed-size output. A 30 MB CSV export or a big HTML error page froze the app, which is the same
|
|
141
|
-
// class of host-app damage as the streaming hang, with the SDK still the cause.
|
|
142
|
-
//
|
|
143
|
-
// The slice is generous (a multiple of the output cap) so redaction still sees enough context to
|
|
144
|
-
// recognise a secret that straddles the boundary, while the work stays bounded regardless of body size.
|
|
145
|
-
const oversized = rawText.length > MAX_BODY_SCAN_CHARS;
|
|
146
|
-
const text = oversized ? rawText.slice(0, MAX_BODY_SCAN_CHARS) : rawText;
|
|
147
|
-
let out;
|
|
148
|
-
if (contentType !== null && /json|graphql/i.test(contentType)) {
|
|
149
|
-
try {
|
|
150
|
-
// safeStringify already sanitizes internally — the extra sanitizeForTransport here re-walked
|
|
151
|
-
// every captured JSON body a second time (~21% of the per-response cost) for an identical result.
|
|
152
|
-
out = safeStringify(JSON.parse(text));
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
out = redactText(text); // looked like JSON but wasn't — still redact key/value + auth tokens
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
out = redactText(text);
|
|
160
|
-
}
|
|
161
|
-
// Key-based redaction can't see a secret sitting in a VALUE under a benign key — scan the projected
|
|
162
|
-
// text for high-confidence secret shapes (JWTs, provider keys) as a backstop, JSON or not.
|
|
163
|
-
out = scrubKnownSecrets(out);
|
|
164
|
-
// Truncated if the projection overflows the cap OR the input itself was clipped above — a body the
|
|
165
|
-
// SDK never fully read must not be reported as complete.
|
|
166
|
-
const truncated = oversized || out.length > MAX_BODY_CHARS;
|
|
167
|
-
return { body: out.length > MAX_BODY_CHARS ? out.slice(0, MAX_BODY_CHARS) : out, truncated };
|
|
168
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Redact credential-bearing values so they don't leak into the agent transcript / flow / run
|
|
3
|
-
* artifacts: query params (`?access_token=…`, signed-URL keys) via the shared `isSensitiveKey` regex,
|
|
4
|
-
* AND path-embedded tokens (`/reset/<token>`, `/invite/<token>`) that live in the path, not the query.
|
|
5
|
-
* The hash is preserved and the URL is returned byte-for-byte when nothing matched.
|
|
6
|
-
*/
|
|
7
|
-
export declare function redactUrl(raw: string): string;
|
|
8
|
-
/**
|
|
9
|
-
* Displayed URL plus, when redaction rewrote it, the raw request for graders.
|
|
10
|
-
*
|
|
11
|
-
* `url` is what the agent reads. `urlRaw` exists only so `urlContains` can still match a public
|
|
12
|
-
* path segment that the heuristic rewrote (`/auth/token/refresh-context`). Omitted when nothing
|
|
13
|
-
* changed, so an ordinary request pays nothing.
|
|
14
|
-
*/
|
|
15
|
-
export declare function netUrlFields(raw: string): {
|
|
16
|
-
url: string;
|
|
17
|
-
} | {
|
|
18
|
-
url: string;
|
|
19
|
-
urlRaw: string;
|
|
20
|
-
};
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { REDACTED_VALUE, URL_RAW } from '@reticlehq/core';
|
|
2
|
-
import { isSensitiveKey } from '../security/serialization.js';
|
|
3
|
-
/** A path segment name that is typically followed by a single-use secret token in the NEXT segment. */
|
|
4
|
-
const SENSITIVE_PATH_SEGMENT = /^(reset|verify|verification|confirm|activate|invite|magic|magiclink|token|key|oauth|unsubscribe|password)$/i;
|
|
5
|
-
/** Only mask a following segment that looks token-like — short ids/words (`reset/form`) are left alone. */
|
|
6
|
-
const PATH_TOKEN_MIN_LENGTH = 12;
|
|
7
|
-
/**
|
|
8
|
-
* Redact credential-bearing values so they don't leak into the agent transcript / flow / run
|
|
9
|
-
* artifacts: query params (`?access_token=…`, signed-URL keys) via the shared `isSensitiveKey` regex,
|
|
10
|
-
* AND path-embedded tokens (`/reset/<token>`, `/invite/<token>`) that live in the path, not the query.
|
|
11
|
-
* The hash is preserved and the URL is returned byte-for-byte when nothing matched.
|
|
12
|
-
*/
|
|
13
|
-
export function redactUrl(raw) {
|
|
14
|
-
const hashStart = raw.indexOf('#');
|
|
15
|
-
const hash = -1 === hashStart ? '' : raw.slice(hashStart);
|
|
16
|
-
const beforeHash = -1 === hashStart ? raw : raw.slice(0, hashStart);
|
|
17
|
-
const queryStart = beforeHash.indexOf('?');
|
|
18
|
-
const pathPart = -1 === queryStart ? beforeHash : beforeHash.slice(0, queryStart);
|
|
19
|
-
const query = -1 === queryStart ? '' : beforeHash.slice(queryStart + 1);
|
|
20
|
-
let changed = false;
|
|
21
|
-
// Credentials in the authority (`scheme://user:pass@host`) never belong in a transcript.
|
|
22
|
-
// Match to the LAST `@` before the path (`[^/]*@`, greedy), not the first — a password containing
|
|
23
|
-
// `@` (`user:p@ss@host`) otherwise left its tail (`ss@host`) in the clear.
|
|
24
|
-
let authority = pathPart;
|
|
25
|
-
const userinfo = /^([a-z][a-z0-9+.-]*:\/\/)[^/]*@/i.exec(pathPart);
|
|
26
|
-
if (userinfo !== null) {
|
|
27
|
-
authority = `${userinfo[1] ?? ''}${REDACTED_VALUE}@${pathPart.slice(userinfo[0].length)}`;
|
|
28
|
-
changed = true;
|
|
29
|
-
}
|
|
30
|
-
let newQuery = query;
|
|
31
|
-
if (query !== '') {
|
|
32
|
-
const params = new URLSearchParams(query);
|
|
33
|
-
let queryChanged = false;
|
|
34
|
-
for (const key of [...params.keys()]) {
|
|
35
|
-
if (isSensitiveKey(key)) {
|
|
36
|
-
params.set(key, REDACTED_VALUE);
|
|
37
|
-
queryChanged = true;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (queryChanged) {
|
|
41
|
-
newQuery = params.toString();
|
|
42
|
-
changed = true;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
const segments = authority.split('/');
|
|
46
|
-
for (let i = 0; i + 1 < segments.length; i++) {
|
|
47
|
-
const name = segments[i];
|
|
48
|
-
const next = segments[i + 1];
|
|
49
|
-
if (name !== undefined &&
|
|
50
|
-
next !== undefined &&
|
|
51
|
-
next.length >= PATH_TOKEN_MIN_LENGTH &&
|
|
52
|
-
SENSITIVE_PATH_SEGMENT.test(name)) {
|
|
53
|
-
segments[i + 1] = REDACTED_VALUE;
|
|
54
|
-
changed = true;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
// OAuth implicit flow puts the access_token in the FRAGMENT (`#access_token=…`), and hash-routers carry
|
|
58
|
-
// `?token=…` in the hash — redact sensitive params there too, leaving plain anchors (`#section`) alone.
|
|
59
|
-
let newHash = hash;
|
|
60
|
-
if (hash.length > 1) {
|
|
61
|
-
newHash = hash.replace(/([A-Za-z0-9_.-]+)=([^&\s]+)/g, (m, key) => isSensitiveKey(key) ? `${key}=${REDACTED_VALUE}` : m);
|
|
62
|
-
if (newHash !== hash)
|
|
63
|
-
changed = true;
|
|
64
|
-
}
|
|
65
|
-
if (!changed)
|
|
66
|
-
return raw;
|
|
67
|
-
const queryOut = -1 === queryStart ? '' : `?${newQuery}`;
|
|
68
|
-
return `${segments.join('/')}${queryOut}${newHash}`;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Displayed URL plus, when redaction rewrote it, the raw request for graders.
|
|
72
|
-
*
|
|
73
|
-
* `url` is what the agent reads. `urlRaw` exists only so `urlContains` can still match a public
|
|
74
|
-
* path segment that the heuristic rewrote (`/auth/token/refresh-context`). Omitted when nothing
|
|
75
|
-
* changed, so an ordinary request pays nothing.
|
|
76
|
-
*/
|
|
77
|
-
export function netUrlFields(raw) {
|
|
78
|
-
const url = redactUrl(raw);
|
|
79
|
-
return url === raw ? { url } : { url, [URL_RAW]: raw };
|
|
80
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The artwork constants are annotated `: string` deliberately.
|
|
3
|
-
*
|
|
4
|
-
* Without the annotation TypeScript infers a literal type, and every one of these SVG and HTML
|
|
5
|
-
* strings is copied verbatim into the emitted `.d.ts` as its own type. That duplicated the artwork
|
|
6
|
-
* into the published package twice over: this file's declarations alone were 16KB of a 900KB
|
|
7
|
-
* budget, carrying type information nobody can use - no caller cares about the literal type of a
|
|
8
|
-
* `<path d=...>`.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Brand marks, inlined. The SDK is bundled into someone else's page: it cannot read
|
|
12
|
-
* `assets/logo/*.svg` from disk at runtime and must never fetch from our own domain, so the mark
|
|
13
|
-
* lives here as a string (same precedent as SEND_ICON in presenter-controls.ts).
|
|
14
|
-
* Minified - editor metadata, clip paths, masks and sub-0.01 precision stripped - and painted
|
|
15
|
-
* with `currentColor` so the mark tracks --reticle-fg instead of hardcoding the export's #FAFAFA.
|
|
16
|
-
*/
|
|
17
|
-
/** Accessible name of the HUD. */
|
|
18
|
-
export declare const BRAND_NAME = "Reticle";
|
|
19
|
-
/** Mark alone (shown in the FAB and compact toolbar). */
|
|
20
|
-
export declare const MARK_SVG: string;
|
|
21
|
-
/** Collapsed FAB control - Reticle mark only. */
|
|
22
|
-
export declare const FAB_TOGGLE_HTML: string;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Synthetic-cursor + click effects - the visible "the agent is acting here" motion. Pure DOM helpers
|
|
3
|
-
* extracted from presenter.ts so the controller stays under the size cap; each is a no-op when its
|
|
4
|
-
* element is absent (the panel may not be mounted). Behavior is unchanged from the inlined methods.
|
|
5
|
-
*/
|
|
6
|
-
/** Fly the synthetic cursor to a viewport point and show it. */
|
|
7
|
-
export declare function moveCursor(cursor: HTMLElement | undefined, x: number, y: number): void;
|
|
8
|
-
/** Briefly draw the green focus ring around an element's box, then fade it. */
|
|
9
|
-
export declare function ringAround(ring: HTMLElement | undefined, rect: DOMRect): void;
|
|
10
|
-
/** Spawn a one-shot click ripple at a viewport point (self-removing). */
|
|
11
|
-
export declare function spawnRipple(root: HTMLElement | undefined, x: number, y: number): void;
|
|
12
|
-
/** Pace for the human so an action is watchable, not instant. */
|
|
13
|
-
export declare function pace(ms: number): Promise<void>;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/** Shared polished-black surfaces used across HUD chrome panels. */
|
|
2
|
-
export declare const HUD_SURFACE_CLASS = "reticle-hud-surface";
|
|
3
|
-
/** Layered near-black base — no embedded image assets. */
|
|
4
|
-
export declare const HUD_SURFACE_FILL: string;
|
|
5
|
-
export declare const HUD_SURFACE_PAINT: string;
|
|
6
|
-
export declare const HUD_DROP_SHADOW: string;
|
|
7
|
-
export declare const HUD_CHROME_CSS: string;
|
|
8
|
-
/** Inset well for the activity log — sits inside the chat card. */
|
|
9
|
-
export declare const HUD_LOG_WELL_CLASS = "reticle-hud-log-well";
|
|
10
|
-
/**
|
|
11
|
-
* The activity feed sits ON the panel, not in a black box cut out of it.
|
|
12
|
-
*
|
|
13
|
-
* The inset well was a second surface inside a surface - two borders, two backgrounds - and it made
|
|
14
|
-
* the panel read as a container rather than as one card. It also grew and shrank with its content,
|
|
15
|
-
* so the panel resized on every row; the height is fixed now and the feed scrolls inside it.
|
|
16
|
-
*/
|
|
17
|
-
export declare const HUD_LOG_WELL_CSS: string;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { PresenterMode } from '@reticlehq/core';
|
|
2
|
-
/** Activity-log entry kinds (presenter-only UI; never a wire string). */
|
|
3
|
-
export declare const LOG_KIND: {
|
|
4
|
-
readonly READ: "read";
|
|
5
|
-
readonly ACT: "act";
|
|
6
|
-
readonly NARRATION: "narration";
|
|
7
|
-
readonly HUMAN: "human";
|
|
8
|
-
};
|
|
9
|
-
export type LogKind = (typeof LOG_KIND)[keyof typeof LOG_KIND];
|
|
10
|
-
/** Act-row outcome glyph keys (presenter-only UI). */
|
|
11
|
-
export declare const LOG_RESULT: {
|
|
12
|
-
readonly PASS: "pass";
|
|
13
|
-
readonly FAIL: "fail";
|
|
14
|
-
};
|
|
15
|
-
export type LogResult = (typeof LOG_RESULT)[keyof typeof LOG_RESULT];
|
|
16
|
-
/** HUD chip copy keyed by presenter mode (UI text, browser-local - not a wire string). */
|
|
17
|
-
export declare const CHIP_LABEL: Record<PresenterMode, string>;
|
|
18
|
-
export declare const DATA_RETICLE_LOG = "data-reticle-log";
|
|
19
|
-
/**
|
|
20
|
-
* The attribute on ONE log line's timestamp. Deliberately not `data-reticle-log-ts`: that name is
|
|
21
|
-
* the overlay-level SETTING (show timestamps y/n) and the overlay root carries it, so a bare
|
|
22
|
-
* `[data-reticle-log-ts]{opacity:.85}` here matched the overlay itself and made the entire HUD -
|
|
23
|
-
* chat panel included - 85% transparent, with the page legible straight through it.
|
|
24
|
-
*/
|
|
25
|
-
export declare const LOG_TIME_ATTR = "data-reticle-log-time";
|
|
26
|
-
/** CSS for the log feed (injected with the rest of the presenter stylesheet; vars inherit from the card). */
|
|
27
|
-
export declare const LOG_CSS: string;
|
|
28
|
-
/**
|
|
29
|
-
* Pin the feed to its newest row.
|
|
30
|
-
*
|
|
31
|
-
* Called on append AND when the chat is opened, because a hidden panel has no layout: rows added
|
|
32
|
-
* while it was minimised could not scroll it, so opening it showed the OLDEST row and the latest
|
|
33
|
-
* activity - the reason to open it - was somewhere below the fold.
|
|
34
|
-
*/
|
|
35
|
-
export declare function scrollLogToLatest(container: HTMLElement): void;
|
|
36
|
-
/**
|
|
37
|
-
* Pin the feed to its newest row once the panel has actually laid out.
|
|
38
|
-
*
|
|
39
|
-
* A single frame is not enough on open: the rows carry `content-visibility:auto`, so their real
|
|
40
|
-
* heights arrive after the first paint and `scrollHeight` keeps growing under a scroll that has
|
|
41
|
-
* already happened - the feed landed a third of the way down instead of at the end. Two frames
|
|
42
|
-
* plus one settle pass costs nothing and lands on the last row.
|
|
43
|
-
*/
|
|
44
|
-
export declare function settleLogAtLatest(container: HTMLElement): void;
|
|
45
|
-
/** Handle returned from logRow/Presenter.log so the caller can stamp the outcome glyph later. */
|
|
46
|
-
export interface LogHandle {
|
|
47
|
-
result(r: LogResult): void;
|
|
48
|
-
}
|
|
49
|
-
/** Clamp a logMax option to a sane positive integer, falling back to the default. */
|
|
50
|
-
export declare function clampLogMax(n: number | undefined): number;
|
|
51
|
-
/**
|
|
52
|
-
* Pure, human-readable duration ("3s", "47s", "2m", "1h 4m") - no clock read, so it stays
|
|
53
|
-
* deterministic in tests. Used for both the per-row timestamp (time since session start) and the
|
|
54
|
-
* live "idle · {duration} since last action" heartbeat. Sub-second reads as "0s".
|
|
55
|
-
*/
|
|
56
|
-
export declare function humanDuration(ms: number): string;
|
|
57
|
-
/** Per-row timestamp: time since the session's first row, human-readable (e.g. "2m", not "+132.4s"). */
|
|
58
|
-
export declare function formatElapsed(ms: number): string;
|
|
59
|
-
/**
|
|
60
|
-
* Build a log row from text (already trimmed) + a +elapsed timestamp, append it to the container,
|
|
61
|
-
* prune to logMax, auto-scroll to newest, and return a handle to stamp the outcome glyph later.
|
|
62
|
-
* Uses createElement/textContent (never innerHTML) so arbitrary narration text can't inject markup.
|
|
63
|
-
*/
|
|
64
|
-
export declare function appendLogRow(container: HTMLElement, kind: LogKind, text: string, ts: string, logMax: number): LogHandle;
|