@holostaff/sdk 0.3.1 → 0.4.1
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/README.md +6 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/observations.d.ts +53 -0
- package/dist/observations.d.ts.map +1 -0
- package/dist/observations.js +143 -0
- package/dist/observations.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/widget.d.ts +27 -17
- package/dist/widget.d.ts.map +1 -1
- package/dist/widget.js +194 -65
- package/dist/widget.js.map +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -50,6 +50,12 @@ pass to `init()`.
|
|
|
50
50
|
- POST identity / stage / signal / outcome events to the Holostaff runtime.
|
|
51
51
|
- Track the current SPA route and last-user-activity time, and forward
|
|
52
52
|
them to the runtime on route changes plus a low-frequency heartbeat.
|
|
53
|
+
- **Record the session with rrweb** (DOM, canvas at ~2 fps, media playback
|
|
54
|
+
state, inlined images/fonts) and batch it to the runtime, where the
|
|
55
|
+
vision pipeline watches the session and decides when the copilot should
|
|
56
|
+
step in. Password / email / tel inputs are always masked; mark rendered
|
|
57
|
+
PII with the `holostaff-mask` (text) or `holostaff-block` (region) CSS
|
|
58
|
+
classes; opt out entirely with `init({ observe: { enabled: false } })`.
|
|
53
59
|
- Hold a server-sent-events channel open and render `text` interventions
|
|
54
60
|
as a shadow-DOM pill (dismiss / engage / 30s auto-ignore), reporting
|
|
55
61
|
outcomes back automatically.
|
|
@@ -57,7 +63,6 @@ pass to `init()`.
|
|
|
57
63
|
**Does not (yet)**
|
|
58
64
|
- Render non-text modalities (voice / email / sms / phone /
|
|
59
65
|
screen automation) — those events are surfaced to `onError` and skipped.
|
|
60
|
-
- Capture rrweb / DOM events — that lives in the Holostaff widget script.
|
|
61
66
|
|
|
62
67
|
## References
|
|
63
68
|
|
package/dist/index.d.ts
CHANGED
|
@@ -36,6 +36,6 @@ export interface HolostaffApi {
|
|
|
36
36
|
_destroy(): void;
|
|
37
37
|
}
|
|
38
38
|
export declare const holostaff: HolostaffApi;
|
|
39
|
-
export type { BowtieStage, InitOptions, InterventionOutcome } from './types.js';
|
|
39
|
+
export type { BowtieStage, InitOptions, InterventionOutcome, ObserveOptions } from './types.js';
|
|
40
40
|
export { BOWTIE_STAGES } from './types.js';
|
|
41
41
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAaH,OAAO,EAAiB,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAmDxG,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,aAAa,IAAI,IAAI,CAAA;IACrB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACxC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACjE;;;;;;OAMG;IACH,aAAa,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAA;IACzE,kCAAkC;IAClC,QAAQ,IAAI,IAAI,CAAA;CACjB;AAED,eAAO,MAAM,SAAS,EAAE,YA4LvB,CAAA;AAED,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC/F,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ import { getOrMintDeviceId, getHostUserId, setHostUserId, clearHostUserId, } fro
|
|
|
21
21
|
import { resolveTransportConfig, postJson, postBeacon, openCommandStream } from './transport.js';
|
|
22
22
|
import { mintSessionId, bindUnload } from './session.js';
|
|
23
23
|
import { startSignals } from './signals.js';
|
|
24
|
+
import { startObservations } from './observations.js';
|
|
24
25
|
import { startWidget } from './widget.js';
|
|
25
26
|
import { BOWTIE_STAGES } from './types.js';
|
|
26
27
|
let state = null;
|
|
@@ -81,6 +82,16 @@ export const holostaff = {
|
|
|
81
82
|
sourceId: opts.sourceId,
|
|
82
83
|
buildBody: () => commonBody(nextState),
|
|
83
84
|
});
|
|
85
|
+
// Vision-reconciliation wave — rrweb capture batched to
|
|
86
|
+
// /observations; the server replays in Browserbase and the Gemini
|
|
87
|
+
// perceive+decide tick runs on what it sees. On by default.
|
|
88
|
+
nextState.observeOpts = opts.observe;
|
|
89
|
+
nextState.observations = startObservations({
|
|
90
|
+
cfg: transport,
|
|
91
|
+
sessionId,
|
|
92
|
+
buildBody: () => commonBody(nextState),
|
|
93
|
+
observe: opts.observe,
|
|
94
|
+
});
|
|
84
95
|
// Wave 3e — widget subscribes to the SSE channel and renders the
|
|
85
96
|
// text pill on `fire_intervention` events. Outcomes flow back to
|
|
86
97
|
// /outcome.
|
|
@@ -149,6 +160,16 @@ export const holostaff = {
|
|
|
149
160
|
sourceId: s.sourceId,
|
|
150
161
|
buildBody: () => commonBody(s),
|
|
151
162
|
});
|
|
163
|
+
// Restart capture too — stopping and re-recording forces a fresh
|
|
164
|
+
// full DOM snapshot, which the new session's replay needs to
|
|
165
|
+
// bootstrap from.
|
|
166
|
+
s.observations?.dispose();
|
|
167
|
+
s.observations = startObservations({
|
|
168
|
+
cfg: s.transport,
|
|
169
|
+
sessionId: s.sessionId,
|
|
170
|
+
buildBody: () => commonBody(s),
|
|
171
|
+
observe: s.observeOpts,
|
|
172
|
+
});
|
|
152
173
|
// Wave 3e — same for the SSE channel + widget. The old session is
|
|
153
174
|
// closed; reopen against the new id so future fire_intervention
|
|
154
175
|
// events reach the correct stream.
|
|
@@ -199,6 +220,7 @@ export const holostaff = {
|
|
|
199
220
|
return;
|
|
200
221
|
state.unload?.dispose();
|
|
201
222
|
state.signals?.dispose();
|
|
223
|
+
state.observations?.dispose();
|
|
202
224
|
state.widget?.dispose();
|
|
203
225
|
state.commands?.close();
|
|
204
226
|
state = null;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAwB,MAAM,gBAAgB,CAAA;AACtH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAsB,MAAM,cAAc,CAAA;AAC5E,OAAO,EAAE,YAAY,EAAuB,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,WAAW,EAAsB,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,aAAa,EAAgE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observations — rrweb session capture (vision-reconciliation wave,
|
|
3
|
+
* Phase A).
|
|
4
|
+
*
|
|
5
|
+
* Records the visitor's session with rrweb and ships event batches to
|
|
6
|
+
* `POST /api/runtime/sessions/:sessionId/observations`, where the
|
|
7
|
+
* server's vision bridge replays them in Browserbase and screenshots
|
|
8
|
+
* feed the Gemini perceive+decide tick.
|
|
9
|
+
*
|
|
10
|
+
* Capture policy (wave doc §Phase A — "everything the user sees,
|
|
11
|
+
* except PII"):
|
|
12
|
+
* - Full DOM, canvas (sampled at ~2 fps — the VLM only ticks every
|
|
13
|
+
* 2–5s), media playback state, fonts + images inlined so replay
|
|
14
|
+
* doesn't depend on URLs staying reachable.
|
|
15
|
+
* - Typed PII never leaves the page: password / email / tel inputs
|
|
16
|
+
* are masked at the keystroke level. Rendered PII is the
|
|
17
|
+
* customer's to mark: `holostaff-mask` masks text content,
|
|
18
|
+
* `holostaff-block` blanks a region, `holostaff-ignore` skips an
|
|
19
|
+
* input entirely.
|
|
20
|
+
*
|
|
21
|
+
* Version pin: rrweb 2.0.0-alpha.4 — MUST match the server's replay
|
|
22
|
+
* bundle (server/src/bowtie/vision/rrweb.bundle.js); recorder and
|
|
23
|
+
* replayer share the event format.
|
|
24
|
+
*
|
|
25
|
+
* Loading: rrweb is imported dynamically so hosts that disable
|
|
26
|
+
* observation (or render server-side) never evaluate it; a failed
|
|
27
|
+
* import degrades to no-capture and routes to onError, per the SDK's
|
|
28
|
+
* fail-soft contract.
|
|
29
|
+
*
|
|
30
|
+
* Batching:
|
|
31
|
+
* - flush every FLUSH_INTERVAL_MS, or at MAX_BATCH_EVENTS, or when
|
|
32
|
+
* the approximate batch size passes MAX_BATCH_BYTES (full
|
|
33
|
+
* snapshots with inlined images are heavy — don't let them queue).
|
|
34
|
+
* - final flush on dispose goes over sendBeacon (survives unload);
|
|
35
|
+
* beacons cap at ~64KB so an oversized final batch is truncated to
|
|
36
|
+
* the most recent events — replay loses the tail of a dying
|
|
37
|
+
* session, never the session.
|
|
38
|
+
*/
|
|
39
|
+
import { type TransportConfig } from './transport.js';
|
|
40
|
+
import type { ObserveOptions } from './types.js';
|
|
41
|
+
export interface ObservationsBindingDeps {
|
|
42
|
+
cfg: TransportConfig;
|
|
43
|
+
sessionId: string;
|
|
44
|
+
/** Common body fields — tenantId/sourceId/deviceId/hostUserId. */
|
|
45
|
+
buildBody: () => Record<string, unknown>;
|
|
46
|
+
observe?: ObserveOptions;
|
|
47
|
+
}
|
|
48
|
+
export interface ObservationsBinding {
|
|
49
|
+
/** Stop recording, flush the tail via beacon. */
|
|
50
|
+
dispose(): void;
|
|
51
|
+
}
|
|
52
|
+
export declare function startObservations(deps: ObservationsBindingDeps): ObservationsBinding;
|
|
53
|
+
//# sourceMappingURL=observations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observations.d.ts","sourceRoot":"","sources":["../src/observations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAOhD,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,eAAe,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,SAAS,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACxC,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,OAAO,IAAI,IAAI,CAAA;CAChB;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,uBAAuB,GAAG,mBAAmB,CAyFpF"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observations — rrweb session capture (vision-reconciliation wave,
|
|
3
|
+
* Phase A).
|
|
4
|
+
*
|
|
5
|
+
* Records the visitor's session with rrweb and ships event batches to
|
|
6
|
+
* `POST /api/runtime/sessions/:sessionId/observations`, where the
|
|
7
|
+
* server's vision bridge replays them in Browserbase and screenshots
|
|
8
|
+
* feed the Gemini perceive+decide tick.
|
|
9
|
+
*
|
|
10
|
+
* Capture policy (wave doc §Phase A — "everything the user sees,
|
|
11
|
+
* except PII"):
|
|
12
|
+
* - Full DOM, canvas (sampled at ~2 fps — the VLM only ticks every
|
|
13
|
+
* 2–5s), media playback state, fonts + images inlined so replay
|
|
14
|
+
* doesn't depend on URLs staying reachable.
|
|
15
|
+
* - Typed PII never leaves the page: password / email / tel inputs
|
|
16
|
+
* are masked at the keystroke level. Rendered PII is the
|
|
17
|
+
* customer's to mark: `holostaff-mask` masks text content,
|
|
18
|
+
* `holostaff-block` blanks a region, `holostaff-ignore` skips an
|
|
19
|
+
* input entirely.
|
|
20
|
+
*
|
|
21
|
+
* Version pin: rrweb 2.0.0-alpha.4 — MUST match the server's replay
|
|
22
|
+
* bundle (server/src/bowtie/vision/rrweb.bundle.js); recorder and
|
|
23
|
+
* replayer share the event format.
|
|
24
|
+
*
|
|
25
|
+
* Loading: rrweb is imported dynamically so hosts that disable
|
|
26
|
+
* observation (or render server-side) never evaluate it; a failed
|
|
27
|
+
* import degrades to no-capture and routes to onError, per the SDK's
|
|
28
|
+
* fail-soft contract.
|
|
29
|
+
*
|
|
30
|
+
* Batching:
|
|
31
|
+
* - flush every FLUSH_INTERVAL_MS, or at MAX_BATCH_EVENTS, or when
|
|
32
|
+
* the approximate batch size passes MAX_BATCH_BYTES (full
|
|
33
|
+
* snapshots with inlined images are heavy — don't let them queue).
|
|
34
|
+
* - final flush on dispose goes over sendBeacon (survives unload);
|
|
35
|
+
* beacons cap at ~64KB so an oversized final batch is truncated to
|
|
36
|
+
* the most recent events — replay loses the tail of a dying
|
|
37
|
+
* session, never the session.
|
|
38
|
+
*/
|
|
39
|
+
import { postJson, postBeacon } from './transport.js';
|
|
40
|
+
const FLUSH_INTERVAL_MS = 5000;
|
|
41
|
+
const MAX_BATCH_EVENTS = 200;
|
|
42
|
+
const MAX_BATCH_BYTES = 800000;
|
|
43
|
+
const BEACON_SAFE_BYTES = 55000;
|
|
44
|
+
export function startObservations(deps) {
|
|
45
|
+
if (typeof window === 'undefined')
|
|
46
|
+
return { dispose: () => { } };
|
|
47
|
+
if (deps.observe?.enabled === false)
|
|
48
|
+
return { dispose: () => { } };
|
|
49
|
+
let disposed = false;
|
|
50
|
+
let stopRecording = null;
|
|
51
|
+
let buffer = [];
|
|
52
|
+
let bufferBytes = 0;
|
|
53
|
+
let flushTimer = null;
|
|
54
|
+
const path = `/api/runtime/sessions/${deps.sessionId}/observations`;
|
|
55
|
+
const flush = () => {
|
|
56
|
+
if (!buffer.length)
|
|
57
|
+
return;
|
|
58
|
+
const events = buffer;
|
|
59
|
+
buffer = [];
|
|
60
|
+
bufferBytes = 0;
|
|
61
|
+
void postJson(deps.cfg, path, { ...deps.buildBody(), events });
|
|
62
|
+
};
|
|
63
|
+
/** Unload-safe flush. Beacon payloads cap at ~64KB; keep the most
|
|
64
|
+
* recent events if the tail batch is oversized — replay loses the
|
|
65
|
+
* tail of a dying session, never the session. */
|
|
66
|
+
const flushBeacon = () => {
|
|
67
|
+
if (!buffer.length)
|
|
68
|
+
return;
|
|
69
|
+
let events = buffer;
|
|
70
|
+
buffer = [];
|
|
71
|
+
bufferBytes = 0;
|
|
72
|
+
// Size by the events alone (body adds ~200 constant bytes); halving
|
|
73
|
+
// converges in ≤4 rounds from the 800KB batch cap.
|
|
74
|
+
while (events.length > 1 && JSON.stringify(events).length > BEACON_SAFE_BYTES) {
|
|
75
|
+
events = events.slice(Math.ceil(events.length / 2));
|
|
76
|
+
}
|
|
77
|
+
postBeacon(deps.cfg, path, { ...deps.buildBody(), events });
|
|
78
|
+
};
|
|
79
|
+
const push = (event) => {
|
|
80
|
+
if (disposed)
|
|
81
|
+
return;
|
|
82
|
+
buffer.push(event);
|
|
83
|
+
// Approximate sizing — exact enough to keep batches under the cap.
|
|
84
|
+
try {
|
|
85
|
+
bufferBytes += JSON.stringify(event).length;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
bufferBytes += 1000;
|
|
89
|
+
}
|
|
90
|
+
if (buffer.length >= MAX_BATCH_EVENTS || bufferBytes >= MAX_BATCH_BYTES)
|
|
91
|
+
flush();
|
|
92
|
+
};
|
|
93
|
+
// Dynamic import keeps rrweb out of hosts that never observe and
|
|
94
|
+
// makes a missing/incompatible module a soft failure.
|
|
95
|
+
void import('rrweb')
|
|
96
|
+
.then((rrweb) => {
|
|
97
|
+
if (disposed)
|
|
98
|
+
return;
|
|
99
|
+
const record = rrweb.record;
|
|
100
|
+
if (typeof record !== 'function') {
|
|
101
|
+
deps.cfg.onError?.(new Error('rrweb.record unavailable'), { method: 'OBSERVE', path });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
stopRecording = record({
|
|
105
|
+
emit: (event) => push(event),
|
|
106
|
+
// -- everything the user sees --
|
|
107
|
+
recordCanvas: true,
|
|
108
|
+
sampling: { canvas: 2 },
|
|
109
|
+
inlineImages: true,
|
|
110
|
+
collectFonts: true,
|
|
111
|
+
// -- except PII --
|
|
112
|
+
maskInputOptions: { password: true, email: true, tel: true },
|
|
113
|
+
maskAllInputs: deps.observe?.maskAllInputs ?? false,
|
|
114
|
+
maskTextClass: 'holostaff-mask',
|
|
115
|
+
blockClass: 'holostaff-block',
|
|
116
|
+
ignoreClass: 'holostaff-ignore',
|
|
117
|
+
...(deps.observe?.blockSelector ? { blockSelector: deps.observe.blockSelector } : {}),
|
|
118
|
+
...(deps.observe?.rrweb ?? {}),
|
|
119
|
+
}) ?? null;
|
|
120
|
+
flushTimer = setInterval(flush, FLUSH_INTERVAL_MS);
|
|
121
|
+
})
|
|
122
|
+
.catch((err) => {
|
|
123
|
+
deps.cfg.onError?.(err instanceof Error ? err : new Error(String(err)), { method: 'OBSERVE', path });
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
dispose() {
|
|
127
|
+
if (disposed)
|
|
128
|
+
return;
|
|
129
|
+
disposed = true;
|
|
130
|
+
if (flushTimer != null) {
|
|
131
|
+
clearInterval(flushTimer);
|
|
132
|
+
flushTimer = null;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
stopRecording?.();
|
|
136
|
+
}
|
|
137
|
+
catch { /* recorder already gone */ }
|
|
138
|
+
stopRecording = null;
|
|
139
|
+
flushBeacon();
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=observations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observations.js","sourceRoot":"","sources":["../src/observations.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -8,7 +8,28 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export type BowtieStage = 'awareness' | 'education' | 'selection' | 'mutual_commit' | 'onboarding' | 'adoption' | 'expansion';
|
|
10
10
|
export declare const BOWTIE_STAGES: readonly BowtieStage[];
|
|
11
|
+
export interface ObserveOptions {
|
|
12
|
+
/** Master switch. Default true — vision-first runtime needs eyes. */
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
/** Mask every input, not just PII types. Default false. */
|
|
15
|
+
maskAllInputs?: boolean;
|
|
16
|
+
/** Extra CSS selector to block (region blanked in capture). */
|
|
17
|
+
blockSelector?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Escape hatch: merged last into the rrweb record() options, so a
|
|
20
|
+
* customer can override anything (e.g. recordCanvas: false).
|
|
21
|
+
*/
|
|
22
|
+
rrweb?: Record<string, unknown>;
|
|
23
|
+
}
|
|
11
24
|
export interface InitOptions {
|
|
25
|
+
/**
|
|
26
|
+
* rrweb session-capture options. Capture is ON by default — the
|
|
27
|
+
* runtime is vision-first and decides from what it sees. Password /
|
|
28
|
+
* email / tel inputs are always masked; mark rendered PII with the
|
|
29
|
+
* `holostaff-mask` / `holostaff-block` CSS classes. Set
|
|
30
|
+
* `observe: { enabled: false }` to opt a host out entirely.
|
|
31
|
+
*/
|
|
32
|
+
observe?: ObserveOptions;
|
|
12
33
|
/** The knowledge source id (e.g. 'cli-source-abc'). Provided by the deploy PR. */
|
|
13
34
|
sourceId: string;
|
|
14
35
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,WAAW,GACX,WAAW,GACX,eAAe,GACf,YAAY,GACZ,UAAU,GACV,WAAW,CAAA;AAEf,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAQtC,CAAA;AAEV,MAAM,WAAW,WAAW;IAC1B,kFAAkF;IAClF,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACtE;AAED,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT,WAAW,GACX,SAAS,GACT,YAAY,GACZ,SAAS,GACT,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,WAAW,GACX,WAAW,GACX,eAAe,GACf,YAAY,GACZ,UAAU,GACV,WAAW,CAAA;AAEf,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAQtC,CAAA;AAEV,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,cAAc,CAAA;IACxB,kFAAkF;IAClF,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACtE;AAED,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT,WAAW,GACX,SAAS,GACT,YAAY,GACZ,SAAS,GACT,SAAS,CAAA"}
|
package/dist/widget.d.ts
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Widget —
|
|
2
|
+
* Widget — the intervention card.
|
|
3
3
|
*
|
|
4
4
|
* Listens to the SSE command channel for `fire_intervention` events
|
|
5
|
-
* and renders
|
|
6
|
-
* dismiss / engage
|
|
5
|
+
* and renders the copilot's message as a card in the host page,
|
|
6
|
+
* reporting dismiss / engage / ignore outcomes back to /outcome.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - Single visible widget at a time. A new event while one is open
|
|
12
|
-
* replaces it (and reports 'ignored' for the prior).
|
|
13
|
-
* - No theming. Inline-styled floating pill, fixed lower-right.
|
|
8
|
+
* Appearance & lifecycle (redesigned with UX best practices after the
|
|
9
|
+
* first live dogfood session — the v1 pill could linger after its
|
|
10
|
+
* outcome resolved and carried no copilot identity):
|
|
14
11
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* - IDENTITY FIRST. Every card leads with the copilot's avatar and
|
|
13
|
+
* name — the visitor always knows who is speaking. Missing avatar
|
|
14
|
+
* degrades to an initial-letter monogram, never an empty box.
|
|
15
|
+
* - RELEVANT OR SILENT. The server stamps the route the decision
|
|
16
|
+
* was made for; if the visitor has navigated since (stale fire),
|
|
17
|
+
* the card is not rendered and the outcome reports 'ignored'.
|
|
18
|
+
* - ANIMATED IN, ANIMATED OUT, THEN GONE. Entry: fade + 12px rise
|
|
19
|
+
* (240ms ease-out). Exit: fade + fall (180ms), and the DOM node is
|
|
20
|
+
* removed on transition end — no ghost cards. `prefers-reduced-
|
|
21
|
+
* motion` skips both.
|
|
22
|
+
* - ATTENTION IS BORROWED, NOT STOLEN. aria-live=polite (no focus
|
|
23
|
+
* steal), auto-ignore after 30s — but the timer PAUSES while the
|
|
24
|
+
* visitor hovers or focuses the card and resumes on leave, so
|
|
25
|
+
* reading slowly never counts as ignoring.
|
|
26
|
+
* - ONE CARD AT A TIME. A new fire animates the old card out (as
|
|
27
|
+
* 'ignored') before the new one enters.
|
|
28
|
+
* - Shadow-DOM isolated: host CSS can't bleed in, ours can't bleed
|
|
29
|
+
* out.
|
|
30
|
+
*
|
|
31
|
+
* Outcomes: ✕ → 'dismissed' · "Got it" → 'engaged' · 30s of unpaused
|
|
32
|
+
* inattention or stale-route skip → 'ignored'.
|
|
18
33
|
*/
|
|
19
34
|
import { type TransportConfig } from './transport.js';
|
|
20
35
|
export interface WidgetBindingDeps {
|
|
@@ -29,10 +44,5 @@ export interface WidgetBindingDeps {
|
|
|
29
44
|
export interface WidgetBinding {
|
|
30
45
|
dispose(): void;
|
|
31
46
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Start the widget subsystem. Subscribes to the SSE `fire_intervention`
|
|
34
|
-
* event and shows the text pill when one arrives. Idempotent in the
|
|
35
|
-
* sense that the SDK singleton ensures one binding per session.
|
|
36
|
-
*/
|
|
37
47
|
export declare function startWidget(deps: WidgetBindingDeps): WidgetBinding;
|
|
38
48
|
//# sourceMappingURL=widget.d.ts.map
|
package/dist/widget.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.d.ts","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"widget.d.ts","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAW/D,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,eAAe,CAAA;IACpB,sFAAsF;IACtF,YAAY,EAAE,MAAM,MAAM,CAAA;IAC1B,mEAAmE;IACnE,SAAS,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACxC,gEAAgE;IAChE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,IAAI,IAAI,CAAA;CAChB;AAaD,wBAAgB,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAoElE"}
|
package/dist/widget.js
CHANGED
|
@@ -1,36 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Widget —
|
|
2
|
+
* Widget — the intervention card.
|
|
3
3
|
*
|
|
4
4
|
* Listens to the SSE command channel for `fire_intervention` events
|
|
5
|
-
* and renders
|
|
6
|
-
* dismiss / engage
|
|
5
|
+
* and renders the copilot's message as a card in the host page,
|
|
6
|
+
* reporting dismiss / engage / ignore outcomes back to /outcome.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - Single visible widget at a time. A new event while one is open
|
|
12
|
-
* replaces it (and reports 'ignored' for the prior).
|
|
13
|
-
* - No theming. Inline-styled floating pill, fixed lower-right.
|
|
8
|
+
* Appearance & lifecycle (redesigned with UX best practices after the
|
|
9
|
+
* first live dogfood session — the v1 pill could linger after its
|
|
10
|
+
* outcome resolved and carried no copilot identity):
|
|
14
11
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* - IDENTITY FIRST. Every card leads with the copilot's avatar and
|
|
13
|
+
* name — the visitor always knows who is speaking. Missing avatar
|
|
14
|
+
* degrades to an initial-letter monogram, never an empty box.
|
|
15
|
+
* - RELEVANT OR SILENT. The server stamps the route the decision
|
|
16
|
+
* was made for; if the visitor has navigated since (stale fire),
|
|
17
|
+
* the card is not rendered and the outcome reports 'ignored'.
|
|
18
|
+
* - ANIMATED IN, ANIMATED OUT, THEN GONE. Entry: fade + 12px rise
|
|
19
|
+
* (240ms ease-out). Exit: fade + fall (180ms), and the DOM node is
|
|
20
|
+
* removed on transition end — no ghost cards. `prefers-reduced-
|
|
21
|
+
* motion` skips both.
|
|
22
|
+
* - ATTENTION IS BORROWED, NOT STOLEN. aria-live=polite (no focus
|
|
23
|
+
* steal), auto-ignore after 30s — but the timer PAUSES while the
|
|
24
|
+
* visitor hovers or focuses the card and resumes on leave, so
|
|
25
|
+
* reading slowly never counts as ignoring.
|
|
26
|
+
* - ONE CARD AT A TIME. A new fire animates the old card out (as
|
|
27
|
+
* 'ignored') before the new one enters.
|
|
28
|
+
* - Shadow-DOM isolated: host CSS can't bleed in, ours can't bleed
|
|
29
|
+
* out.
|
|
30
|
+
*
|
|
31
|
+
* Outcomes: ✕ → 'dismissed' · "Got it" → 'engaged' · 30s of unpaused
|
|
32
|
+
* inattention or stale-route skip → 'ignored'.
|
|
18
33
|
*/
|
|
19
34
|
import { postJson } from './transport.js';
|
|
20
|
-
/** Auto-
|
|
35
|
+
/** Auto-ignore timeout — runtime doc §9.1 'ignored' outcome. */
|
|
21
36
|
const AUTO_DISMISS_MS = 30000;
|
|
37
|
+
const ENTER_MS = 240;
|
|
38
|
+
const EXIT_MS = 180;
|
|
22
39
|
/** Container id — single instance per page. */
|
|
23
40
|
const CONTAINER_ID = 'holostaff-widget-root';
|
|
24
|
-
/**
|
|
25
|
-
* Start the widget subsystem. Subscribes to the SSE `fire_intervention`
|
|
26
|
-
* event and shows the text pill when one arrives. Idempotent in the
|
|
27
|
-
* sense that the SDK singleton ensures one binding per session.
|
|
28
|
-
*/
|
|
29
41
|
export function startWidget(deps) {
|
|
30
42
|
if (typeof window === 'undefined' || !deps.source) {
|
|
31
43
|
return { dispose: () => { } };
|
|
32
44
|
}
|
|
33
45
|
let currentWidget = null;
|
|
46
|
+
const reportOutcome = (interventionId, outcome) => {
|
|
47
|
+
void postJson(deps.cfg, `/api/runtime/sessions/${deps.getSessionId()}/outcome`, {
|
|
48
|
+
...deps.buildBody(),
|
|
49
|
+
interventionId,
|
|
50
|
+
outcome,
|
|
51
|
+
});
|
|
52
|
+
};
|
|
34
53
|
const onFire = (rawEvent) => {
|
|
35
54
|
let parsed = null;
|
|
36
55
|
try {
|
|
@@ -44,12 +63,22 @@ export function startWidget(deps) {
|
|
|
44
63
|
}
|
|
45
64
|
if (!parsed)
|
|
46
65
|
return;
|
|
47
|
-
// Modality gate — only text is
|
|
66
|
+
// Modality gate — only text is renderable in this build.
|
|
48
67
|
if (parsed.modality !== 'text') {
|
|
49
68
|
deps.cfg.onError?.(new Error(`Modality '${parsed.modality}' is not supported in this SDK build`), { method: 'WIDGET', path: '(fire_intervention)' });
|
|
50
69
|
return;
|
|
51
70
|
}
|
|
52
|
-
//
|
|
71
|
+
// Stale-fire guard: the decision was made for a route the visitor
|
|
72
|
+
// has already left. Showing it now would be a non-sequitur — skip
|
|
73
|
+
// the render, close the loop as 'ignored'.
|
|
74
|
+
if (parsed.route) {
|
|
75
|
+
const decidedPath = parsed.route.split('?')[0];
|
|
76
|
+
if (decidedPath && decidedPath !== window.location.pathname) {
|
|
77
|
+
reportOutcome(parsed.interventionId, 'ignored');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// One card at a time — retire the old one as 'ignored'.
|
|
53
82
|
if (currentWidget) {
|
|
54
83
|
currentWidget.reportAndClose('ignored');
|
|
55
84
|
}
|
|
@@ -73,59 +102,131 @@ export function startWidget(deps) {
|
|
|
73
102
|
function renderWidget(deps, event, onClosed) {
|
|
74
103
|
const container = ensureContainer();
|
|
75
104
|
const root = container.shadowRoot;
|
|
76
|
-
//
|
|
105
|
+
// Defensive single-card invariant.
|
|
77
106
|
root.innerHTML = '';
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
107
|
+
const reducedMotion = typeof window.matchMedia === 'function'
|
|
108
|
+
&& window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
109
|
+
const card = document.createElement('div');
|
|
110
|
+
card.className = 'card enter';
|
|
111
|
+
card.setAttribute('role', 'status');
|
|
112
|
+
card.setAttribute('aria-live', 'polite');
|
|
113
|
+
card.setAttribute('data-intervention-id', event.interventionId);
|
|
114
|
+
// -- Header: avatar + name + dismiss ---------------------------------
|
|
115
|
+
const head = document.createElement('div');
|
|
116
|
+
head.className = 'head';
|
|
117
|
+
const copilotName = event.copilot?.name?.trim() || 'Copilot';
|
|
118
|
+
const avatarUrl = event.copilot?.avatar?.trim() || '';
|
|
119
|
+
if (avatarUrl) {
|
|
120
|
+
const avatar = document.createElement('img');
|
|
121
|
+
avatar.className = 'avatar';
|
|
122
|
+
avatar.src = avatarUrl;
|
|
123
|
+
avatar.alt = '';
|
|
124
|
+
avatar.referrerPolicy = 'no-referrer';
|
|
125
|
+
// Broken avatar URL → swap in the monogram rather than the
|
|
126
|
+
// browser's broken-image glyph.
|
|
127
|
+
avatar.addEventListener('error', () => {
|
|
128
|
+
avatar.replaceWith(monogram(copilotName));
|
|
129
|
+
});
|
|
130
|
+
head.appendChild(avatar);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
head.appendChild(monogram(copilotName));
|
|
134
|
+
}
|
|
135
|
+
const name = document.createElement('div');
|
|
136
|
+
name.className = 'name';
|
|
137
|
+
name.textContent = copilotName;
|
|
138
|
+
head.appendChild(name);
|
|
139
|
+
const dismissBtn = document.createElement('button');
|
|
140
|
+
dismissBtn.className = 'x';
|
|
141
|
+
dismissBtn.type = 'button';
|
|
142
|
+
dismissBtn.setAttribute('aria-label', 'Dismiss');
|
|
143
|
+
dismissBtn.textContent = '✕';
|
|
144
|
+
head.appendChild(dismissBtn);
|
|
145
|
+
// -- Message + actions ------------------------------------------------
|
|
83
146
|
const message = document.createElement('div');
|
|
84
147
|
message.className = 'message';
|
|
85
148
|
message.textContent = event.content || event.goal;
|
|
86
149
|
const actions = document.createElement('div');
|
|
87
150
|
actions.className = 'actions';
|
|
88
|
-
const dismissBtn = document.createElement('button');
|
|
89
|
-
dismissBtn.className = 'btn dismiss';
|
|
90
|
-
dismissBtn.type = 'button';
|
|
91
|
-
dismissBtn.textContent = 'Dismiss';
|
|
92
151
|
const engageBtn = document.createElement('button');
|
|
93
152
|
engageBtn.className = 'btn engage';
|
|
94
153
|
engageBtn.type = 'button';
|
|
95
154
|
engageBtn.textContent = 'Got it';
|
|
96
|
-
actions.appendChild(dismissBtn);
|
|
97
155
|
actions.appendChild(engageBtn);
|
|
98
|
-
|
|
99
|
-
|
|
156
|
+
card.appendChild(head);
|
|
157
|
+
card.appendChild(message);
|
|
158
|
+
card.appendChild(actions);
|
|
100
159
|
root.appendChild(styleNode());
|
|
101
|
-
root.appendChild(
|
|
160
|
+
root.appendChild(card);
|
|
161
|
+
// Entry animation — next frame so the transition actually runs.
|
|
162
|
+
if (reducedMotion) {
|
|
163
|
+
card.classList.remove('enter');
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
requestAnimationFrame(() => requestAnimationFrame(() => card.classList.remove('enter')));
|
|
167
|
+
}
|
|
168
|
+
// -- Auto-ignore timer: pauses on hover/focus, resumes on leave ------
|
|
102
169
|
let closed = false;
|
|
103
|
-
let
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
170
|
+
let remainingMs = AUTO_DISMISS_MS;
|
|
171
|
+
let deadlineTimer = null;
|
|
172
|
+
let timerStartedAt = 0;
|
|
173
|
+
const startTimer = () => {
|
|
174
|
+
if (closed)
|
|
175
|
+
return;
|
|
176
|
+
timerStartedAt = Date.now();
|
|
177
|
+
deadlineTimer = setTimeout(() => instance.reportAndClose('ignored'), remainingMs);
|
|
178
|
+
};
|
|
179
|
+
const pauseTimer = () => {
|
|
180
|
+
if (deadlineTimer == null)
|
|
181
|
+
return;
|
|
182
|
+
clearTimeout(deadlineTimer);
|
|
183
|
+
deadlineTimer = null;
|
|
184
|
+
remainingMs = Math.max(1000, remainingMs - (Date.now() - timerStartedAt));
|
|
185
|
+
};
|
|
186
|
+
card.addEventListener('mouseenter', pauseTimer);
|
|
187
|
+
card.addEventListener('focusin', pauseTimer);
|
|
188
|
+
card.addEventListener('mouseleave', startTimer);
|
|
189
|
+
card.addEventListener('focusout', startTimer);
|
|
190
|
+
startTimer();
|
|
191
|
+
const sendOutcome = (outcome) => {
|
|
192
|
+
void postJson(deps.cfg, `/api/runtime/sessions/${deps.getSessionId()}/outcome`, {
|
|
108
193
|
...deps.buildBody(),
|
|
109
194
|
interventionId: event.interventionId,
|
|
110
195
|
outcome,
|
|
111
|
-
};
|
|
112
|
-
void postJson(deps.cfg, `/api/runtime/sessions/${deps.getSessionId()}/outcome`, body);
|
|
196
|
+
});
|
|
113
197
|
};
|
|
114
198
|
const close = (outcome) => {
|
|
115
199
|
if (closed)
|
|
116
200
|
return;
|
|
117
201
|
closed = true;
|
|
118
|
-
if (
|
|
119
|
-
clearTimeout(
|
|
120
|
-
|
|
202
|
+
if (deadlineTimer != null) {
|
|
203
|
+
clearTimeout(deadlineTimer);
|
|
204
|
+
deadlineTimer = null;
|
|
121
205
|
}
|
|
122
206
|
if (outcome)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
207
|
+
sendOutcome(outcome);
|
|
208
|
+
const remove = () => {
|
|
209
|
+
try {
|
|
210
|
+
root.removeChild(card);
|
|
211
|
+
}
|
|
212
|
+
catch { /* removed already */ }
|
|
213
|
+
onClosed();
|
|
214
|
+
};
|
|
215
|
+
if (reducedMotion) {
|
|
216
|
+
remove();
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
card.classList.add('exit');
|
|
220
|
+
// transitionend can be swallowed if the tab is hidden — back it
|
|
221
|
+
// up with a timeout so the node ALWAYS leaves the DOM.
|
|
222
|
+
let removed = false;
|
|
223
|
+
const once = () => { if (!removed) {
|
|
224
|
+
removed = true;
|
|
225
|
+
remove();
|
|
226
|
+
} };
|
|
227
|
+
card.addEventListener('transitionend', once, { once: true });
|
|
228
|
+
setTimeout(once, EXIT_MS + 80);
|
|
126
229
|
}
|
|
127
|
-
catch { /* removed already */ }
|
|
128
|
-
onClosed();
|
|
129
230
|
};
|
|
130
231
|
dismissBtn.addEventListener('click', () => close('dismissed'));
|
|
131
232
|
engageBtn.addEventListener('click', () => close('engaged'));
|
|
@@ -136,6 +237,12 @@ function renderWidget(deps, event, onClosed) {
|
|
|
136
237
|
};
|
|
137
238
|
return instance;
|
|
138
239
|
}
|
|
240
|
+
function monogram(name) {
|
|
241
|
+
const el = document.createElement('div');
|
|
242
|
+
el.className = 'avatar mono';
|
|
243
|
+
el.textContent = (name.trim()[0] ?? '?').toUpperCase();
|
|
244
|
+
return el;
|
|
245
|
+
}
|
|
139
246
|
function ensureContainer() {
|
|
140
247
|
let el = document.getElementById(CONTAINER_ID);
|
|
141
248
|
if (el)
|
|
@@ -149,33 +256,55 @@ function ensureContainer() {
|
|
|
149
256
|
}
|
|
150
257
|
function styleNode() {
|
|
151
258
|
const node = document.createElement('style');
|
|
152
|
-
//
|
|
259
|
+
// Shadow-DOM scoped; no host page leakage either direction.
|
|
153
260
|
node.textContent = `
|
|
154
|
-
.
|
|
261
|
+
.card {
|
|
155
262
|
pointer-events: auto;
|
|
156
|
-
|
|
263
|
+
width: 340px;
|
|
264
|
+
max-width: calc(100vw - 32px);
|
|
157
265
|
background: #111;
|
|
158
266
|
color: #fafafa;
|
|
159
|
-
border-radius:
|
|
267
|
+
border-radius: 16px;
|
|
160
268
|
box-shadow: 0 12px 32px rgba(0,0,0,0.32), 0 2px 8px rgba(0,0,0,0.12);
|
|
161
|
-
padding: 14px
|
|
162
|
-
font: 14px/1.
|
|
269
|
+
padding: 12px 14px 12px;
|
|
270
|
+
font: 14px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
|
|
271
|
+
opacity: 1;
|
|
272
|
+
transform: translateY(0);
|
|
273
|
+
transition: opacity ${ENTER_MS}ms ease-out, transform ${ENTER_MS}ms ease-out;
|
|
163
274
|
}
|
|
164
|
-
.
|
|
165
|
-
.
|
|
275
|
+
.card.enter { opacity: 0; transform: translateY(12px); }
|
|
276
|
+
.card.exit { opacity: 0; transform: translateY(12px); transition-duration: ${EXIT_MS}ms; }
|
|
277
|
+
.head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
|
|
278
|
+
.avatar {
|
|
279
|
+
width: 36px; height: 36px; border-radius: 50%;
|
|
280
|
+
object-fit: cover; flex: none;
|
|
281
|
+
background: #2a2a2a;
|
|
282
|
+
}
|
|
283
|
+
.avatar.mono {
|
|
284
|
+
display: flex; align-items: center; justify-content: center;
|
|
285
|
+
color: #9ab8ff; font-weight: 600; font-size: 16px;
|
|
286
|
+
}
|
|
287
|
+
.name { font-weight: 600; font-size: 13px; color: #e8e8e8; flex: 1; }
|
|
288
|
+
.x {
|
|
289
|
+
appearance: none; border: 0; background: transparent;
|
|
290
|
+
color: #8a8a8a; font-size: 13px; line-height: 1;
|
|
291
|
+
padding: 6px; margin: -6px -4px -6px 0; border-radius: 8px;
|
|
292
|
+
cursor: pointer; flex: none;
|
|
293
|
+
}
|
|
294
|
+
.x:hover { color: #fff; background: rgba(255,255,255,0.08); }
|
|
295
|
+
.message { margin: 0 2px 12px; color: #f2f2f2; }
|
|
296
|
+
.actions { display: flex; justify-content: flex-end; }
|
|
166
297
|
.btn {
|
|
167
|
-
appearance: none;
|
|
168
|
-
border:
|
|
169
|
-
|
|
170
|
-
border-radius: 8px;
|
|
171
|
-
font: inherit;
|
|
172
|
-
font-size: 13px;
|
|
298
|
+
appearance: none; border: 0;
|
|
299
|
+
padding: 7px 14px; border-radius: 9px;
|
|
300
|
+
font: inherit; font-size: 13px; font-weight: 500;
|
|
173
301
|
cursor: pointer;
|
|
174
302
|
}
|
|
175
|
-
.btn.dismiss { background: transparent; color: #c7c7c7; }
|
|
176
|
-
.btn.dismiss:hover { color: #fff; }
|
|
177
303
|
.btn.engage { background: #4f8bff; color: #fff; }
|
|
178
304
|
.btn.engage:hover { background: #6aa0ff; }
|
|
305
|
+
.btn:focus-visible, .x:focus-visible {
|
|
306
|
+
outline: 2px solid #9ab8ff; outline-offset: 2px;
|
|
307
|
+
}
|
|
179
308
|
`;
|
|
180
309
|
return node;
|
|
181
310
|
}
|
package/dist/widget.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,QAAQ,EAAwB,MAAM,gBAAgB,CAAA;AAG/D,gEAAgE;AAChE,MAAM,eAAe,GAAG,KAAM,CAAA;AAC9B,MAAM,QAAQ,GAAG,GAAG,CAAA;AACpB,MAAM,OAAO,GAAG,GAAG,CAAA;AAEnB,+CAA+C;AAC/C,MAAM,YAAY,GAAG,uBAAuB,CAAA;AA2B5C,MAAM,UAAU,WAAW,CAAC,IAAuB;IACjD,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAA;IAC9B,CAAC;IAED,IAAI,aAAa,GAA0B,IAAI,CAAA;IAE/C,MAAM,aAAa,GAAG,CAAC,cAAsB,EAAE,OAA4B,EAAQ,EAAE;QACnF,KAAK,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,yBAAyB,IAAI,CAAC,YAAY,EAAE,UAAU,EAAE;YAC9E,GAAG,IAAI,CAAC,SAAS,EAAE;YACnB,cAAc;YACd,OAAO;SACR,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,CAAC,QAAsB,EAAQ,EAAE;QAC9C,IAAI,MAAM,GAAqB,IAAI,CAAA;QACnC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAc,CAAA;YACnD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ;gBAAE,OAAM;YAC5D,MAAM,GAAG,IAAI,CAAA;QACf,CAAC;QAAC,MAAM,CAAC;YACP,OAAM;QACR,CAAC;QACD,IAAI,CAAC,MAAM;YAAE,OAAM;QAEnB,yDAAyD;QACzD,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC/B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAChB,IAAI,KAAK,CAAC,aAAa,MAAM,CAAC,QAAQ,sCAAsC,CAAC,EAC7E,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAClD,CAAA;YACD,OAAM;QACR,CAAC;QAED,kEAAkE;QAClE,kEAAkE;QAClE,2CAA2C;QAC3C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YAC9C,IAAI,WAAW,IAAI,WAAW,KAAK,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBAC5D,aAAa,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,CAAA;gBAC/C,OAAM;YACR,CAAC;QACH,CAAC;QAED,wDAAwD;QACxD,IAAI,aAAa,EAAE,CAAC;YAClB,aAAa,CAAC,cAAc,CAAC,SAAS,CAAC,CAAA;QACzC,CAAC;QACD,aAAa,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;YAC9C,IAAI,aAAa,IAAI,aAAa,CAAC,KAAK,CAAC,cAAc,KAAK,MAAO,CAAC,cAAc,EAAE,CAAC;gBACnF,aAAa,GAAG,IAAI,CAAA;YACtB,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,MAAuB,CAAC,CAAA;IAE1E,OAAO;QACL,OAAO;YACL,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,mBAAmB,EAAE,MAAuB,CAAC,CAAA;YAC9E,IAAI,aAAa,EAAE,CAAC;gBAClB,aAAa,CAAC,MAAM,EAAE,CAAA;gBACtB,aAAa,GAAG,IAAI,CAAA;YACtB,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAcD,SAAS,YAAY,CACnB,IAAuB,EACvB,KAAgB,EAChB,QAAoB;IAEpB,MAAM,SAAS,GAAG,eAAe,EAAE,CAAA;IACnC,MAAM,IAAI,GAAG,SAAS,CAAC,UAAW,CAAA;IAElC,mCAAmC;IACnC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAA;IAEnB,MAAM,aAAa,GAAG,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;WACxD,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO,CAAA;IAElE,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC1C,IAAI,CAAC,SAAS,GAAG,YAAY,CAAA;IAC7B,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACnC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;IACxC,IAAI,CAAC,YAAY,CAAC,sBAAsB,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IAE/D,uEAAuE;IACvE,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC1C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAA;IAEvB,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,SAAS,CAAA;IAC5D,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACrD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;QAC5C,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAA;QAC3B,MAAM,CAAC,GAAG,GAAG,SAAS,CAAA;QACtB,MAAM,CAAC,GAAG,GAAG,EAAE,CAAA;QACf,MAAM,CAAC,cAAc,GAAG,aAAa,CAAA;QACrC,2DAA2D;QAC3D,gCAAgC;QAChC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACpC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;QAC3C,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;IAC1B,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;IACzC,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC1C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAA;IACvB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;IAC9B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAEtB,MAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;IACnD,UAAU,CAAC,SAAS,GAAG,GAAG,CAAA;IAC1B,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAA;IAC1B,UAAU,CAAC,YAAY,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;IAChD,UAAU,CAAC,WAAW,GAAG,GAAG,CAAA;IAC5B,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;IAE5B,wEAAwE;IACxE,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC7C,OAAO,CAAC,SAAS,GAAG,SAAS,CAAA;IAC7B,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAA;IAEjD,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC7C,OAAO,CAAC,SAAS,GAAG,SAAS,CAAA;IAC7B,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;IAClD,SAAS,CAAC,SAAS,GAAG,YAAY,CAAA;IAClC,SAAS,CAAC,IAAI,GAAG,QAAQ,CAAA;IACzB,SAAS,CAAC,WAAW,GAAG,QAAQ,CAAA;IAChC,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;IAE9B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IACtB,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACzB,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACzB,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,CAAA;IAC7B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAEtB,gEAAgE;IAChE,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAChC,CAAC;SAAM,CAAC;QACN,qBAAqB,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC1F,CAAC;IAED,uEAAuE;IACvE,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,IAAI,WAAW,GAAG,eAAe,CAAA;IACjC,IAAI,aAAa,GAAyC,IAAI,CAAA;IAC9D,IAAI,cAAc,GAAG,CAAC,CAAA;IAEtB,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,IAAI,MAAM;YAAE,OAAM;QAClB,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC3B,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,CAAA;IACnF,CAAC,CAAA;IACD,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,IAAI,aAAa,IAAI,IAAI;YAAE,OAAM;QACjC,YAAY,CAAC,aAAa,CAAC,CAAA;QAC3B,aAAa,GAAG,IAAI,CAAA;QACpB,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAK,EAAE,WAAW,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC,CAAC,CAAA;IAC5E,CAAC,CAAA;IACD,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;IAC/C,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;IAC5C,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;IAC/C,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;IAC7C,UAAU,EAAE,CAAA;IAEZ,MAAM,WAAW,GAAG,CAAC,OAA4B,EAAQ,EAAE;QACzD,KAAK,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,yBAAyB,IAAI,CAAC,YAAY,EAAE,UAAU,EAAE;YAC9E,GAAG,IAAI,CAAC,SAAS,EAAE;YACnB,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,OAAO;SACR,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,CAAC,OAAmC,EAAQ,EAAE;QAC1D,IAAI,MAAM;YAAE,OAAM;QAClB,MAAM,GAAG,IAAI,CAAA;QACb,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;YAAC,YAAY,CAAC,aAAa,CAAC,CAAC;YAAC,aAAa,GAAG,IAAI,CAAA;QAAC,CAAC;QAChF,IAAI,OAAO;YAAE,WAAW,CAAC,OAAO,CAAC,CAAA;QACjC,MAAM,MAAM,GAAG,GAAS,EAAE;YACxB,IAAI,CAAC;gBAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC;YAC9D,QAAQ,EAAE,CAAA;QACZ,CAAC,CAAA;QACD,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,EAAE,CAAA;QACV,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAC1B,gEAAgE;YAChE,uDAAuD;YACvD,IAAI,OAAO,GAAG,KAAK,CAAA;YACnB,MAAM,IAAI,GAAG,GAAS,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;gBAAC,OAAO,GAAG,IAAI,CAAC;gBAAC,MAAM,EAAE,CAAA;YAAC,CAAC,CAAC,CAAC,CAAA;YACvE,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;YAC5D,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,EAAE,CAAC,CAAA;QAChC,CAAC;IACH,CAAC,CAAA;IAED,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAA;IAC9D,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAA;IAE3D,MAAM,QAAQ,GAAmB;QAC/B,KAAK;QACL,cAAc,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA,CAAC,CAAC;QAC1C,MAAM,KAAK,KAAK,CAAC,IAAI,CAAC,CAAA,CAAC,CAAC;KACzB,CAAA;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IACxC,EAAE,CAAC,SAAS,GAAG,aAAa,CAAA;IAC5B,EAAE,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;IACtD,OAAO,EAAE,CAAA;AACX,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;IAC9C,IAAI,EAAE;QAAE,OAAO,EAAE,CAAA;IACjB,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAClC,EAAE,CAAC,EAAE,GAAG,YAAY,CAAA;IACpB,EAAE,CAAC,KAAK,CAAC,OAAO,GAAG,8EAA8E,CAAA;IACjG,EAAE,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IACjC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;IAC7B,OAAO,EAAE,CAAA;AACX,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IAC5C,4DAA4D;IAC5D,IAAI,CAAC,WAAW,GAAG;;;;;;;;;;;;;4BAaO,QAAQ,0BAA0B,QAAQ;;;kFAGY,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCtF,CAAA;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holostaff/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Holostaff SDK — lifetime identity, stage detection, custom signal probes, and the intervention widget for the Holostaff runtime.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://docs.holostaff.ai",
|
|
@@ -38,5 +38,8 @@
|
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"typescript": "^5.4.0"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"rrweb": "^2.0.0-alpha.4"
|
|
41
44
|
}
|
|
42
45
|
}
|