@volter/teams 0.1.21 → 0.1.23
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/package.json +1 -1
- package/viewer/index.html +9 -5
- package/viewer/session-view-entry.mjs +28 -3
- package/viewer/session-view.mjs +23 -22
- package/viewer/viewer.mjs +34 -2
package/viewer/viewer.mjs
CHANGED
|
@@ -10,13 +10,32 @@ const $ = (id) => document.getElementById(id);
|
|
|
10
10
|
const decoder = new TextDecoder();
|
|
11
11
|
const status = (text) => { $('status').textContent = text; };
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
const fragment = new URLSearchParams(location.hash.slice(1));
|
|
14
|
+
let token = fragment.get('token');
|
|
14
15
|
history.replaceState(null, '', location.pathname);
|
|
15
16
|
let waiting = null;
|
|
16
17
|
|
|
17
18
|
const embedded = window.parent !== window;
|
|
18
19
|
const ask = (type) => { if (embedded) window.parent.postMessage({ type }, '*'); };
|
|
20
|
+
// The host's style, as supercode-ui is themed: its `--volter-*` brand tokens and `--scui-*` component tokens, set on
|
|
21
|
+
// the session's root (every component reads them from an ancestor). Nothing else is taken from the host.
|
|
22
|
+
function applyTheme(properties) {
|
|
23
|
+
if (!properties || typeof properties !== 'object') return;
|
|
24
|
+
for (const [name, value] of Object.entries(properties)) {
|
|
25
|
+
if (!/^--(volter|scui)-[a-z0-9-]+$/.test(name) || typeof value !== 'string' || value.length > 400) continue;
|
|
26
|
+
// on the page (its background) and on the session root (which sets its own scheme default)
|
|
27
|
+
for (const element of [document.documentElement, $('session')]) element.style.setProperty(name, value);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// The session header is the host's to show: framed, it is hidden unless the host asks for it (the host's own header
|
|
31
|
+
// carries the session's details, which this page posts to it as `viewer-session`).
|
|
32
|
+
function showHeader(shown) { $('session').classList.toggle('header-hidden', !shown); }
|
|
33
|
+
try { applyTheme(JSON.parse(atob((fragment.get('theme') ?? '').replaceAll('-', '+').replaceAll('_', '/')) || 'null')); } catch { /* no theme */ }
|
|
34
|
+
showHeader(fragment.has('header') ? fragment.get('header') !== 'hidden' : !embedded);
|
|
35
|
+
|
|
19
36
|
window.addEventListener('message', (event) => {
|
|
37
|
+
if (event.data?.type === 'viewer-theme') { applyTheme(event.data.properties); return; }
|
|
38
|
+
if (event.data?.type === 'viewer-header') { showHeader(!event.data.hidden); return; }
|
|
20
39
|
if (event.data?.type !== 'delegated-token' || typeof event.data.token !== 'string') return;
|
|
21
40
|
token = event.data.token;
|
|
22
41
|
if (waiting) { const resume = waiting; waiting = null; resume(); }
|
|
@@ -74,6 +93,8 @@ async function showSession(session, control) {
|
|
|
74
93
|
element.hidden = false;
|
|
75
94
|
const view = mountSessionView(element, {
|
|
76
95
|
control,
|
|
96
|
+
// The name the Room gives this session's agent (the token's session.agentName), else "Agent".
|
|
97
|
+
agentName: typeof session.agentName === 'string' && session.agentName.trim() ? session.agentName.trim().slice(0, 80) : null,
|
|
77
98
|
onSend: async (text) => {
|
|
78
99
|
view.update({ sending: true });
|
|
79
100
|
try {
|
|
@@ -86,7 +107,18 @@ async function showSession(session, control) {
|
|
|
86
107
|
},
|
|
87
108
|
});
|
|
88
109
|
const headers = async () => ({ Authorization: `Bearer ${await freshToken()}` });
|
|
89
|
-
const
|
|
110
|
+
const HARNESSES = { 'claude-code': 'Claude Code', codex: 'Codex', gemini: 'Gemini CLI', goose: 'Goose', opencode: 'OpenCode', pi: 'Pi', grok: 'Grok' };
|
|
111
|
+
const apply = (body) => {
|
|
112
|
+
view.update({ descriptor: body.descriptor, messages: body.messages.map((message) => message.value), members: body.names?.members ?? [], machines: body.names?.machines ?? [], status: 'ready', error: null });
|
|
113
|
+
// What the host's own header shows about this session: who owns it, what runs it, where, and what this viewer may do.
|
|
114
|
+
const descriptor = body.descriptor ?? {};
|
|
115
|
+
const owner = (body.names?.members ?? []).find((member) => member.principal?.id === descriptor.user?.principal_id)?.principal?.display_name ?? descriptor.user?.reported_user ?? null;
|
|
116
|
+
if (embedded) window.parent.postMessage({ type: 'viewer-session', session: {
|
|
117
|
+
id: descriptor.id ?? session.id, title: descriptor.title ?? null, harness: descriptor.harness ?? null, harnessLabel: HARNESSES[descriptor.harness] ?? descriptor.harness ?? null,
|
|
118
|
+
owner, machines: (descriptor.machine_ids ?? []).map((id) => (body.names?.machines ?? []).find((machine) => machine.id === id)?.name ?? id),
|
|
119
|
+
scope: control ? 'control' : 'view', working: body.working ?? null,
|
|
120
|
+
} }, '*');
|
|
121
|
+
};
|
|
90
122
|
let reading = null;
|
|
91
123
|
const read = () => (reading ??= (async () => {
|
|
92
124
|
try {
|