clay-server 5.2.0-beta.3 → 5.2.0-beta.4
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/lib/builtin-mates.js +2 -2
- package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
- package/lib/knowledge-file-store.js +7 -1
- package/lib/mate-avatar-catalog.js +12 -0
- package/lib/mate-avatar-migration.js +41 -0
- package/lib/mates.js +14 -3
- package/lib/mcp-agent-tools.js +117 -0
- package/lib/mcp-connection-store.js +119 -15
- package/lib/mcp-import-credentials.js +31 -0
- package/lib/mcp-local-transport.js +13 -0
- package/lib/mcp-oauth.js +8 -6
- package/lib/mcp-query-bridge.js +30 -0
- package/lib/mcp-remote-connections.js +74 -20
- package/lib/mcp-source-adapters.js +91 -0
- package/lib/mcp-source-context.js +42 -0
- package/lib/mcp-source-discovery.js +169 -0
- package/lib/mcp-source-plugins.js +68 -0
- package/lib/mcp-source-restrictions.js +47 -0
- package/lib/mcp-tool-policy.js +34 -0
- package/lib/project-ask-user.js +6 -4
- package/lib/project-debate.js +1 -0
- package/lib/project-mate-interaction.js +8 -0
- package/lib/project-mcp.js +54 -16
- package/lib/project-session-document.js +8 -3
- package/lib/project-session-github.js +16 -7
- package/lib/project-session-linear.js +14 -6
- package/lib/project-session-notes.js +7 -3
- package/lib/project-sessions.js +6 -2
- package/lib/project-shared-browser.js +56 -12
- package/lib/project.js +49 -34
- package/lib/public/app.js +5 -0
- package/lib/public/appearance-bootstrap.js +14 -0
- package/lib/public/css/clay-workspace.css +29 -0
- package/lib/public/css/home-debate-planning.css +2 -0
- package/lib/public/css/mate-avatar-gallery.css +12 -0
- package/lib/public/css/mate-conversation.css +10 -5
- package/lib/public/css/session-github.css +43 -1
- package/lib/public/css/shared-browser.css +35 -1
- package/lib/public/index.html +10 -4
- package/lib/public/mate-avatars/B01.png +0 -0
- package/lib/public/mate-avatars/B02.png +0 -0
- package/lib/public/mate-avatars/B03.png +0 -0
- package/lib/public/mate-avatars/B04.png +0 -0
- package/lib/public/mate-avatars/B05.png +0 -0
- package/lib/public/mate-avatars/B06.png +0 -0
- package/lib/public/mate-avatars/B07.png +0 -0
- package/lib/public/mate-avatars/B08.png +0 -0
- package/lib/public/mate-avatars/B09.png +0 -0
- package/lib/public/mate-avatars/B10.png +0 -0
- package/lib/public/mate-avatars/B11.png +0 -0
- package/lib/public/mate-avatars/B12.png +0 -0
- package/lib/public/mate-avatars/B13.png +0 -0
- package/lib/public/mate-avatars/B14.png +0 -0
- package/lib/public/mate-avatars/B15.png +0 -0
- package/lib/public/mate-avatars/B16.png +0 -0
- package/lib/public/mate-avatars/B17.png +0 -0
- package/lib/public/mate-avatars/B18.png +0 -0
- package/lib/public/mate-avatars/B19.png +0 -0
- package/lib/public/mate-avatars/B20.png +0 -0
- package/lib/public/mate-avatars/B21.png +0 -0
- package/lib/public/mate-avatars/B22.png +0 -0
- package/lib/public/mate-avatars/B23.png +0 -0
- package/lib/public/mate-avatars/B24.png +0 -0
- package/lib/public/mate-avatars/B25.png +0 -0
- package/lib/public/mate-avatars/B26.png +0 -0
- package/lib/public/mate-avatars/B27.png +0 -0
- package/lib/public/mate-avatars/B28.png +0 -0
- package/lib/public/mate-avatars/B29.png +0 -0
- package/lib/public/mate-avatars/B30.png +0 -0
- package/lib/public/mate-avatars/B31.png +0 -0
- package/lib/public/mate-avatars/B32.png +0 -0
- package/lib/public/mate-avatars/B33.png +0 -0
- package/lib/public/mate-avatars/B34.png +0 -0
- package/lib/public/mate-avatars/B35.png +0 -0
- package/lib/public/mate-avatars/B36.png +0 -0
- package/lib/public/mate-avatars/B37.png +0 -0
- package/lib/public/mate-avatars/B38.png +0 -0
- package/lib/public/mate-avatars/B39.png +0 -0
- package/lib/public/mate-avatars/B40.png +0 -0
- package/lib/public/mate-avatars/B41.png +0 -0
- package/lib/public/mate-avatars/B42.png +0 -0
- package/lib/public/mate-avatars/B43.png +0 -0
- package/lib/public/mate-avatars/B44.png +0 -0
- package/lib/public/mate-avatars/B45.png +0 -0
- package/lib/public/mate-avatars/B46.png +0 -0
- package/lib/public/mate-avatars/B47.png +0 -0
- package/lib/public/mate-avatars/B48.png +0 -0
- package/lib/public/mate-avatars/C01.png +0 -0
- package/lib/public/mate-avatars/C02.png +0 -0
- package/lib/public/mate-avatars/C03.png +0 -0
- package/lib/public/mate-avatars/C04.png +0 -0
- package/lib/public/mate-avatars/C05.png +0 -0
- package/lib/public/mate-avatars/C06.png +0 -0
- package/lib/public/mate-avatars/C07.png +0 -0
- package/lib/public/mate-avatars/C08.png +0 -0
- package/lib/public/mate-avatars/C09.png +0 -0
- package/lib/public/mate-avatars/C10.png +0 -0
- package/lib/public/mate-avatars/C11.png +0 -0
- package/lib/public/mate-avatars/C12.png +0 -0
- package/lib/public/mate-avatars/C13.png +0 -0
- package/lib/public/mate-avatars/C14.png +0 -0
- package/lib/public/mate-avatars/C15.png +0 -0
- package/lib/public/mate-avatars/C16.png +0 -0
- package/lib/public/mate-avatars/C17.png +0 -0
- package/lib/public/mate-avatars/C18.png +0 -0
- package/lib/public/mate-avatars/C19.png +0 -0
- package/lib/public/mate-avatars/C20.png +0 -0
- package/lib/public/mate-avatars/C21.png +0 -0
- package/lib/public/mate-avatars/C22.png +0 -0
- package/lib/public/mate-avatars/C23.png +0 -0
- package/lib/public/mate-avatars/C24.png +0 -0
- package/lib/public/mate-avatars/C25.png +0 -0
- package/lib/public/mate-avatars/C26.png +0 -0
- package/lib/public/mate-avatars/C27.png +0 -0
- package/lib/public/mate-avatars/C28.png +0 -0
- package/lib/public/mate-avatars/C29.png +0 -0
- package/lib/public/mate-avatars/C30.png +0 -0
- package/lib/public/mate-avatars/C31.png +0 -0
- package/lib/public/mate-avatars/C32.png +0 -0
- package/lib/public/mate-avatars/C33.png +0 -0
- package/lib/public/mate-avatars/C34.png +0 -0
- package/lib/public/mate-avatars/C35.png +0 -0
- package/lib/public/mate-avatars/C36.png +0 -0
- package/lib/public/mate-avatars/C37.png +0 -0
- package/lib/public/mate-avatars/C38.png +0 -0
- package/lib/public/mate-avatars/C39.png +0 -0
- package/lib/public/mate-avatars/C40.png +0 -0
- package/lib/public/mate-avatars/C41.png +0 -0
- package/lib/public/mate-avatars/C42.png +0 -0
- package/lib/public/mate-avatars/C43.png +0 -0
- package/lib/public/mate-avatars/C44.png +0 -0
- package/lib/public/mate-avatars/C45.png +0 -0
- package/lib/public/mate-avatars/C46.png +0 -0
- package/lib/public/mate-avatars/C47.png +0 -0
- package/lib/public/mate-avatars/C48.png +0 -0
- package/lib/public/mate-avatars/catalog.json +482 -0
- package/lib/public/mate-avatars/lead-clay.png +0 -0
- package/lib/public/modules/app-message-router.js +4 -0
- package/lib/public/modules/app-messages.js +13 -2
- package/lib/public/modules/app-rendering.js +1 -1
- package/lib/public/modules/avatar.js +15 -41
- package/lib/public/modules/chat-render-runtime.js +10 -1
- package/lib/public/modules/clay-browser-links.js +47 -0
- package/lib/public/modules/clay-log-links.js +1 -1
- package/lib/public/modules/command-palette.js +1 -1
- package/lib/public/modules/debate.js +1 -0
- package/lib/public/modules/history-replay-batch.js +5 -1
- package/lib/public/modules/home-debate-live.js +2 -0
- package/lib/public/modules/home-debate-planning.js +7 -7
- package/lib/public/modules/home-mate-avatar-editor.js +127 -208
- package/lib/public/modules/home-mate-chat.js +6 -6
- package/lib/public/modules/home-mate-settings.js +19 -12
- package/lib/public/modules/markdown.js +4 -0
- package/lib/public/modules/mate-avatar-catalog.js +97 -0
- package/lib/public/modules/mate-management.js +40 -7
- package/lib/public/modules/mcp-connection-view.js +31 -13
- package/lib/public/modules/mcp-discovery-view.js +31 -0
- package/lib/public/modules/mcp-ui.js +23 -4
- package/lib/public/modules/mention.js +3 -0
- package/lib/public/modules/pane-browser-bridge.js +20 -0
- package/lib/public/modules/profile.js +1 -238
- package/lib/public/modules/project-mate-navigation.js +99 -14
- package/lib/public/modules/search-clay-chat.js +16 -2
- package/lib/public/modules/session-github.js +23 -9
- package/lib/public/modules/session-work-primary.js +51 -0
- package/lib/public/modules/shared-browser-settings.js +112 -0
- package/lib/public/modules/shared-browser-tabs.js +13 -3
- package/lib/public/modules/shared-browser.js +27 -6
- package/lib/public/modules/split-view.js +2 -0
- package/lib/public/modules/theme.js +8 -1
- package/lib/public/modules/tools.js +2 -1
- package/lib/public/style.css +1 -0
- package/lib/public/sw.js +3 -1
- package/lib/sdk-bridge.js +9 -3
- package/lib/server-appearance-settings.js +13 -1
- package/lib/server-dm.js +1 -0
- package/lib/server-home-chat-events.js +14 -4
- package/lib/server-home-chat.js +10 -2
- package/lib/server-home-mcp-consent.js +14 -0
- package/lib/server-mates.js +6 -1
- package/lib/server-settings.js +4 -1
- package/lib/server.js +45 -12
- package/lib/session-work-primary.js +50 -0
- package/lib/sessions.js +3 -0
- package/lib/shared-browser-cookie-sync.js +32 -0
- package/lib/shared-browser-cookies.js +79 -0
- package/lib/shared-browser-runtime.js +25 -9
- package/lib/shared-browser-storage-sync.js +43 -0
- package/lib/shared-browser-storage.js +101 -0
- package/lib/shared-browser-tools.js +2 -1
- package/lib/shared-browser-worker.js +46 -10
- package/lib/yoke/acp-agent-profiles.js +2 -2
- package/package.json +5 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getWs } from './ws-ref.js';
|
|
3
|
+
import { escapeHtml as escapeText } from './utils.js';
|
|
4
|
+
|
|
5
|
+
function escapeHtml(value) { return escapeText(String(value)).replace(/"/g, '"').replace(/'/g, '''); }
|
|
6
|
+
function state() { return store.get('sharedBrowserSettings') || {}; }
|
|
7
|
+
function set(patch) { store.set({ sharedBrowserSettings: Object.assign({}, state(), patch) }); }
|
|
8
|
+
function root() { return document.getElementById('shared-browser-settings'); }
|
|
9
|
+
function button(label, action, target, description) {
|
|
10
|
+
return '<button type="button" data-settings-action="' + action + '" data-target="' + escapeHtml(target || '') + '" data-label="' + escapeHtml(description || target || '') + '">' + escapeHtml(label) + '</button>';
|
|
11
|
+
}
|
|
12
|
+
function request(operation, target) {
|
|
13
|
+
var ws = getWs();
|
|
14
|
+
if (!ws || ws.readyState !== 1) { set({ error: 'Reconnect to manage browser data.', pending: false }); renderBrowserSettings(); return; }
|
|
15
|
+
var id = crypto.randomUUID();
|
|
16
|
+
set({ pending: true, requestId: id, error: '', notice: '' });
|
|
17
|
+
ws.send(JSON.stringify({ type: 'shared_browser_settings', sessionId: store.get('activeSessionId'), requestId: id, operation: operation, target: target }));
|
|
18
|
+
renderBrowserSettings();
|
|
19
|
+
setTimeout(function () {
|
|
20
|
+
if (state().requestId === id && state().pending) { set({ pending: false, error: 'The request timed out. Refresh to check the saved state.' }); renderBrowserSettings(); }
|
|
21
|
+
}, 15000);
|
|
22
|
+
}
|
|
23
|
+
export function closeBrowserSettings(restoreFocus) {
|
|
24
|
+
var wasOpen = !!state().open;
|
|
25
|
+
set({ open: false, review: null }); renderBrowserSettings();
|
|
26
|
+
var trigger = document.querySelector('[data-action="settings"]'); if (trigger && wasOpen && restoreFocus !== false) trigger.focus();
|
|
27
|
+
}
|
|
28
|
+
export function browserSettingsHtml() {
|
|
29
|
+
return '<section id="shared-browser-settings" class="shared-browser-settings" aria-label="Browser settings" hidden></section>';
|
|
30
|
+
}
|
|
31
|
+
export function bindBrowserSettings(panel) {
|
|
32
|
+
panel.querySelector('[data-action="settings"]').onclick = function () {
|
|
33
|
+
set({ open: true, page: 'sites', data: null, review: null, filter: '' });
|
|
34
|
+
request('list');
|
|
35
|
+
root().querySelector('[data-settings-action="back"]').focus();
|
|
36
|
+
};
|
|
37
|
+
root().addEventListener('keydown', function (event) {
|
|
38
|
+
if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); closeBrowserSettings(); }
|
|
39
|
+
});
|
|
40
|
+
root().addEventListener('input', function (event) {
|
|
41
|
+
if (event.target.matches('[data-settings-filter]')) { set({ filter: event.target.value }); renderRows(); root().dataset.key = JSON.stringify([state(), store.get('connected')]); }
|
|
42
|
+
});
|
|
43
|
+
root().addEventListener('click', function (event) {
|
|
44
|
+
var control = event.target.closest('[data-settings-action]');
|
|
45
|
+
if (!control || control.disabled) return;
|
|
46
|
+
var action = control.dataset.settingsAction;
|
|
47
|
+
if (action === 'back') { closeBrowserSettings(); return; }
|
|
48
|
+
if (action === 'sites' || action === 'history') { set({ page: action, filter: '', review: null, notice: '', error: '' }); renderBrowserSettings(); return; }
|
|
49
|
+
if (action === 'refresh') { request('list'); return; }
|
|
50
|
+
if (action === 'cancel') { set({ review: null }); renderBrowserSettings(); root().querySelector('[data-settings-action="refresh"]').focus(); return; }
|
|
51
|
+
if (action === 'confirm') { var review = state().review; if (review) request(review.action, review.target); return; }
|
|
52
|
+
set({ notice: '', error: '', review: { action: action, target: control.dataset.target, label: control.dataset.label || control.dataset.target } });
|
|
53
|
+
renderBrowserSettings(); root().querySelector('[data-settings-action="cancel"]').focus();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function renderRows() {
|
|
57
|
+
var el = root(), s = state(); if (!el || !s.open) return;
|
|
58
|
+
var rows = el.querySelector('.browser-settings-rows'); if (!rows) return;
|
|
59
|
+
var filter = (s.filter || '').toLowerCase();
|
|
60
|
+
var data = s.data || { sites: [], history: [] };
|
|
61
|
+
if (s.page === 'history') {
|
|
62
|
+
rows.innerHTML = data.history.filter(function (entry) { return entry.url.toLowerCase().includes(filter); }).map(function (entry) {
|
|
63
|
+
return '<div class="browser-settings-row"><div><span class="browser-settings-url">' + escapeHtml(entry.url) + '</span><small>' + escapeHtml(new Date(entry.at).toLocaleString()) + '</small></div>' + button('Remove', 'delete_history', entry.id, entry.url) + '</div>';
|
|
64
|
+
}).join('');
|
|
65
|
+
} else {
|
|
66
|
+
rows.innerHTML = data.sites.filter(function (site) { return site.host.toLowerCase().includes(filter); }).map(function (site) {
|
|
67
|
+
return '<details><summary>' + escapeHtml(site.host) + '<small>' + site.cookies.length + (site.cookies.length === 1 ? ' cookie · ' : ' cookies · ') + site.origins.length + (site.origins.length === 1 ? ' storage origin' : ' storage origins') + '</small></summary><div class="browser-settings-row"><span>Cookies and site storage</span>' + button('Remove site data', 'delete_site', site.host) + '</div>' +
|
|
68
|
+
site.origins.map(function (origin) { return '<p class="browser-settings-origin">' + escapeHtml(origin.origin) + '<small>' + origin.localStorage + ' localStorage entries · ' + origin.databases + ' IndexedDB databases</small></p>'; }).join('') +
|
|
69
|
+
site.cookies.map(function (cookie) {
|
|
70
|
+
var info = cookie.domain + cookie.path + ' · ' + (cookie.expires === -1 ? 'Session cookie' : 'Expires ' + new Date(cookie.expires * 1000).toLocaleDateString()) + (cookie.httpOnly ? ' · HttpOnly' : '') + (cookie.secure ? ' · Secure' : '') + (cookie.partitioned ? ' · Partitioned' : '');
|
|
71
|
+
return '<div class="browser-settings-row"><div><span>' + escapeHtml(cookie.name) + '</span><small>' + escapeHtml(info) + '</small></div>' + button('Remove cookie', 'delete_cookie', cookie.id, cookie.name + ' · ' + cookie.domain + cookie.path) + '</div>';
|
|
72
|
+
}).join('') + '</details>';
|
|
73
|
+
}).join('');
|
|
74
|
+
}
|
|
75
|
+
if (!rows.innerHTML) rows.innerHTML = '<p class="browser-settings-muted">' + (s.pending && !s.data ? 'Loading saved data…' : filter ? 'No matching entries.' : s.page === 'history' ? 'No saved browsing history.' : 'No saved cookies or site data.') + '</p>';
|
|
76
|
+
rows.querySelectorAll('button').forEach(function (control) { control.disabled = !!s.pending || !store.get('connected'); });
|
|
77
|
+
}
|
|
78
|
+
export function renderBrowserSettings() {
|
|
79
|
+
var el = root(); if (!el) return;
|
|
80
|
+
var s = state(), panel = el.closest('.shared-browser-panel');
|
|
81
|
+
var browser = store.get('sharedBrowser');
|
|
82
|
+
var trigger = panel.querySelector('[data-action="settings"]');
|
|
83
|
+
trigger.hidden = !(browser && browser.personalCookiesAvailable);
|
|
84
|
+
trigger.disabled = !store.get('connected');
|
|
85
|
+
trigger.setAttribute('aria-expanded', String(!!s.open));
|
|
86
|
+
el.hidden = !s.open;
|
|
87
|
+
panel.classList.toggle('browser-settings-open', !!s.open);
|
|
88
|
+
if (!s.open) return;
|
|
89
|
+
var key = JSON.stringify([s, store.get('connected')]); if (el.dataset.key === key) return; el.dataset.key = key;
|
|
90
|
+
var page = s.page || 'sites';
|
|
91
|
+
el.innerHTML = '<div class="browser-settings-heading">' + button('Back to browser', 'back') + '<h3>Browser settings</h3></div><p class="browser-settings-muted">Personal · Shared across your Mates. Incognito tabs do not save data here.</p>' +
|
|
92
|
+
'<nav aria-label="Browser settings sections">' + button('Cookies & site data', 'sites') + button('History', 'history') + '</nav>' +
|
|
93
|
+
'<p class="browser-settings-muted">' + (page === 'sites' ? 'Cookies, localStorage and IndexedDB are saved for your account. New personal tabs restore saved site storage. Removing data may sign you out. Removals also apply to open personal tabs. Sites may create new data afterwards.' : 'Your latest 500 page visits. Clearing this list leaves open tabs, their Back/Forward navigation and conversation activity unchanged.') + '</p>' +
|
|
94
|
+
'<div class="browser-settings-tools"><input data-settings-filter aria-label="Filter saved browser data" placeholder="' + (page === 'sites' ? 'Find a site' : 'Find a page') + '" value="' + escapeHtml(s.filter || '') + '">' + button('Refresh', 'refresh') + button(page === 'sites' ? 'Clear all site data' : 'Clear history', page === 'sites' ? 'clear_data' : 'clear_history') + '</div>' +
|
|
95
|
+
'<p class="browser-settings-feedback" role="status">' + escapeHtml(s.error || (!store.get('connected') ? 'Disconnected. Reconnect and refresh to see current saved data.' : s.pending ? 'Updating…' : s.notice || '')) + '</p>' +
|
|
96
|
+
(s.review ? '<div class="browser-settings-review" role="group" aria-label="Confirm removal"><strong>' + (s.review.action.includes('history') ? 'Remove browsing history?' : 'Remove saved site data?') + '</strong><p>' + (s.review.action.includes('history') ? 'This removes ' + (s.review.action === 'clear_history' ? 'all saved visits' : 'this saved visit') + ' from your personal history.' : s.review.action === 'delete_cookie' ? 'This removes ' + escapeHtml(s.review.label) + ' across your personal Mate browsers and may sign you out.' : 'This removes ' + (s.review.action === 'clear_data' ? 'all cookies and site storage' : 'cookies and storage for ' + escapeHtml(s.review.target)) + ' across your personal Mate browsers and may sign you out.') + '</p>' + button('Cancel', 'cancel') + button('Remove', 'confirm') + '</div>' : '') +
|
|
97
|
+
'<div class="browser-settings-rows"></div>';
|
|
98
|
+
el.querySelector('[data-settings-action="' + page + '"]').setAttribute('aria-current', 'page');
|
|
99
|
+
el.querySelectorAll('button').forEach(function (control) { control.disabled = control.dataset.settingsAction !== 'back' && (!!s.pending || !store.get('connected')); });
|
|
100
|
+
renderRows();
|
|
101
|
+
}
|
|
102
|
+
export function handleBrowserSettingsMessage(msg) {
|
|
103
|
+
if (!msg.requestId || msg.requestId !== state().requestId) return false;
|
|
104
|
+
if (msg.type === 'shared_browser_settings') {
|
|
105
|
+
var removed = !!state().review;
|
|
106
|
+
set({ data: msg.settings, pending: false, review: null, error: '', notice: removed ? 'Removed from your saved browser data.' : '' });
|
|
107
|
+
} else if (msg.type === 'shared_browser_error') set({ pending: false, error: msg.error });
|
|
108
|
+
else return false;
|
|
109
|
+
renderBrowserSettings();
|
|
110
|
+
if (state().open && removed) root().querySelector('[data-settings-action="refresh"]').focus();
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
1
2
|
import { store } from './store.js';
|
|
2
3
|
|
|
3
4
|
export function renderBrowserTabs(el, select, send) {
|
|
4
5
|
var bar = el.querySelector('.shared-browser-tabs');
|
|
5
6
|
var tabs = store.get('sharedBrowsers') || [];
|
|
6
7
|
var selected = store.get('sharedBrowser');
|
|
7
|
-
var key = JSON.stringify([tabs.map(function (tab) { return [tab.id, tab.url, tab.control, tab.phase]; }), selected && selected.id, store.get('connected')]);
|
|
8
|
+
var key = JSON.stringify([tabs.map(function (tab) { return [tab.id, tab.url, tab.control, tab.phase, tab.incognito, tab.personalCookiesAvailable]; }), selected && selected.id, store.get('connected')]);
|
|
8
9
|
if (bar.dataset.key === key) return;
|
|
9
10
|
bar.dataset.key = key;
|
|
10
11
|
bar.replaceChildren();
|
|
@@ -14,9 +15,9 @@ export function renderBrowserTabs(el, select, send) {
|
|
|
14
15
|
button.setAttribute('aria-selected', String(!!selected && selected.id === tab.id));
|
|
15
16
|
var title = 'Tab ' + (index + 1);
|
|
16
17
|
try { if (tab.url) title = new URL(tab.url).hostname; } catch (e) {}
|
|
17
|
-
var label = document.createElement('span'); label.textContent = title;
|
|
18
|
+
var label = document.createElement('span'); label.textContent = title + (tab.personalCookiesAvailable && tab.incognito ? ' · Incognito' : '');
|
|
18
19
|
var owner = document.createElement('small'); owner.textContent = tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'Shared' : 'You only';
|
|
19
|
-
button.append(label, owner); button.title = title + ' · ' + (tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'You and Clay can control this tab' : 'Only you can control this tab. Clay is paused.');
|
|
20
|
+
button.append(label, owner); button.title = title + ' · ' + (tab.incognito === false ? 'Personal browser' : 'Incognito') + ' · ' + (tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'You and Clay can control this tab' : 'Only you can control this tab. Clay is paused.');
|
|
20
21
|
button.onclick = function () { select(tab.id); };
|
|
21
22
|
button.onkeydown = function (event) {
|
|
22
23
|
var next = event.key === 'ArrowRight' ? (index + 1) % tabs.length : event.key === 'ArrowLeft' ? (index + tabs.length - 1) % tabs.length : event.key === 'Home' ? 0 : event.key === 'End' ? tabs.length - 1 : -1;
|
|
@@ -28,6 +29,15 @@ export function renderBrowserTabs(el, select, send) {
|
|
|
28
29
|
item.append(button, close); bar.appendChild(item);
|
|
29
30
|
});
|
|
30
31
|
var add = document.createElement('button'); add.type = 'button'; add.textContent = '+'; add.setAttribute('aria-label', 'New browser tab'); add.disabled = !store.get('connected');
|
|
32
|
+
add.title = selected && selected.personalCookiesAvailable ? 'New tab · Personal browser' : 'New incognito tab';
|
|
31
33
|
add.onclick = function () { send('open', { newTab: true }); };
|
|
32
34
|
bar.appendChild(add);
|
|
35
|
+
if (selected && selected.personalCookiesAvailable) {
|
|
36
|
+
var incognito = document.createElement('button'); incognito.type = 'button';
|
|
37
|
+
incognito.innerHTML = iconHtml('glasses');
|
|
38
|
+
incognito.setAttribute('aria-label', 'New incognito tab'); incognito.title = 'New incognito tab · Site data is not saved';
|
|
39
|
+
incognito.disabled = !store.get('connected');
|
|
40
|
+
incognito.onclick = function () { send('open', { newTab: true, incognito: true }); };
|
|
41
|
+
bar.appendChild(incognito); refreshIcons();
|
|
42
|
+
}
|
|
33
43
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { browserLinkTarget, initBrowserLinks } from './clay-browser-links.js';
|
|
2
|
+
import { browserSettingsHtml, bindBrowserSettings, renderBrowserSettings, closeBrowserSettings, handleBrowserSettingsMessage } from './shared-browser-settings.js';
|
|
1
3
|
import { renderBrowserTabs } from './shared-browser-tabs.js';
|
|
2
4
|
import { store } from './store.js';
|
|
3
5
|
import { getWs } from './ws-ref.js';
|
|
@@ -50,15 +52,15 @@ function ensurePanel() {
|
|
|
50
52
|
el.className = 'shared-browser-panel hidden';
|
|
51
53
|
el.setAttribute('aria-label', 'Shared browser');
|
|
52
54
|
el.innerHTML = '<header class="shared-browser-header"><span class="shared-browser-title">' + iconHtml('globe') + 'Browser</span><span class="shared-browser-phase" role="status">Ready</span><div class="shared-browser-window">' +
|
|
53
|
-
iconButton('wide', 'chevrons-left-right', 'Widen browser panel') + iconButton('fullscreen', 'maximize-2', 'Toggle browser fullscreen') + iconButton('hide', 'x', 'Hide browser panel') + '</div></header>' +
|
|
55
|
+
iconButton('settings', 'settings-2', 'Browser settings') + iconButton('wide', 'chevrons-left-right', 'Widen browser panel') + iconButton('fullscreen', 'maximize-2', 'Toggle browser fullscreen') + iconButton('hide', 'x', 'Hide browser panel') + '</div></header>' +
|
|
54
56
|
'<div class="shared-browser-tabs" role="tablist" aria-label="Browser tabs"></div><form class="shared-browser-address">' + iconButton('back', 'arrow-left', 'Back') + iconButton('forward', 'arrow-right', 'Forward') + iconButton('reload', 'rotate-cw', 'Reload') +
|
|
55
57
|
'<input aria-label="Browser address" placeholder="Enter a URL" type="text" autocomplete="off" spellcheck="false"><button type="submit" aria-label="Open address">' + iconHtml('arrow-right') + '</button></form>' +
|
|
56
|
-
'<div class="shared-browser-viewport"><div class="shared-browser-monitor"><div class="shared-browser-pointer-layer" aria-hidden="true"><div class="shared-browser-pointer" hidden><svg viewBox="0 0 24 28"><path d="M3 2 L3 22 L8 17 L12 26 L16 24 L12 15 L20 15 Z"/></svg><i></i></div></div><canvas width="1280" height="800" tabindex="0" aria-label="Shared browser page"></canvas>' +
|
|
57
|
-
'<div class="shared-browser-empty">' + iconHtml('globe') + '<h3>A browser you can
|
|
58
|
+
browserSettingsHtml() + '<div class="shared-browser-viewport"><div class="shared-browser-monitor"><div class="shared-browser-pointer-layer" aria-hidden="true"><div class="shared-browser-pointer" hidden><svg viewBox="0 0 24 28"><path d="M3 2 L3 22 L8 17 L12 26 L16 24 L12 15 L20 15 Z"/></svg><i></i></div></div><canvas width="1280" height="800" tabindex="0" aria-label="Shared browser page"></canvas>' +
|
|
59
|
+
'<div class="shared-browser-empty">' + iconHtml('globe') + '<h3>A browser you can use with Clay</h3><p>Enter an address to browse together.<br>Localhost connects to the Clay host.</p><p class="shared-browser-private">Site data lasts only for this browser session.</p></div>' +
|
|
58
60
|
'<textarea class="shared-browser-keyboard" aria-label="Type into shared browser" autocomplete="off" autocapitalize="off" spellcheck="false"></textarea><span class="shared-browser-monitor-brand" aria-hidden="true">Clay Studio</span><span class="shared-browser-monitor-detail" aria-hidden="true"></span><span class="shared-browser-monitor-stand" aria-hidden="true"></span></div><div class="shared-browser-caption"><span class="shared-browser-monitor-label"></span>' + activityHtml() + '</div></div>' +
|
|
59
61
|
'<p class="shared-browser-error hidden" role="status"></p>' +
|
|
60
62
|
'<footer class="shared-browser-footer"><div class="shared-browser-control"><span class="shared-browser-control-status" role="status" aria-live="polite">You and Clay can control this browser</span><button type="button" data-action="control" aria-pressed="false"></button></div>' +
|
|
61
|
-
'<div class="shared-browser-details">' + viewportMenuHtml() + '<button type="button" data-action="end">End browser</button></div></footer>';
|
|
63
|
+
'<div class="shared-browser-details"><span class="shared-browser-cookie-mode"></span>' + viewportMenuHtml() + '<button type="button" data-action="end">End browser</button></div></footer>';
|
|
62
64
|
root.appendChild(el);
|
|
63
65
|
el.querySelector('[data-action="hide"]').onclick = hideSharedBrowser;
|
|
64
66
|
el.querySelector('[data-action="wide"]').onclick = function () { var wide = !(store.get('sharedBrowserUi') || {}).wide; ui({ wide: wide }); render(); };
|
|
@@ -69,8 +71,9 @@ function ensurePanel() {
|
|
|
69
71
|
var browser = store.get('sharedBrowser');
|
|
70
72
|
if (browser) send('control', { control: browser.control === 'user' ? 'agent' : 'user' });
|
|
71
73
|
};
|
|
72
|
-
el.querySelector('[data-action="end"]').onclick = function () { var browser = store.get('sharedBrowser'); send(browser && browser.phase === 'ended' ? 'open' : 'end'); };
|
|
74
|
+
el.querySelector('[data-action="end"]').onclick = function () { var browser = store.get('sharedBrowser'); send(browser && browser.phase === 'ended' ? 'open' : 'end', browser && browser.phase === 'ended' ? { incognito: browser.incognito } : undefined); };
|
|
73
75
|
bindViewportMenu(el);
|
|
76
|
+
bindBrowserSettings(el);
|
|
74
77
|
var observer = new ResizeObserver(layoutMonitor);
|
|
75
78
|
observer.observe(el.querySelector('.shared-browser-viewport'));
|
|
76
79
|
bindBrowserInput(el.querySelector('canvas'), el.querySelector('textarea'));
|
|
@@ -141,11 +144,16 @@ function render() {
|
|
|
141
144
|
el.querySelector('[data-action="control"]').hidden = !live;
|
|
142
145
|
el.querySelector('[data-action="end"]').disabled = !browser || !connected;
|
|
143
146
|
el.querySelector('[data-action="end"]').textContent = browser && browser.phase === 'ended' ? 'New browser' : 'End browser';
|
|
147
|
+
var personal = browser && browser.incognito === false;
|
|
148
|
+
el.querySelector('.shared-browser-cookie-mode').textContent = personal ? 'Personal browser' : 'Incognito';
|
|
149
|
+
el.querySelector('.shared-browser-cookie-mode').title = personal ? 'Cookies and site storage are saved for your account across your Mates.' : 'Cookies and site storage are isolated and discarded when this tab ends.';
|
|
150
|
+
el.querySelector('.shared-browser-private').textContent = personal ? 'Your cookies and site storage are remembered across your Mates and browser restarts.' : 'Site data lasts only for this browser session.';
|
|
144
151
|
var error = state.error || (browser && browser.error) || '';
|
|
145
152
|
el.querySelector('.shared-browser-error').textContent = error;
|
|
146
153
|
el.querySelector('.shared-browser-error').classList.toggle('hidden', !error);
|
|
147
154
|
el.querySelector('.shared-browser-empty').classList.toggle('hidden', !!(browser && browser.url && state.hasFrame));
|
|
148
155
|
renderViewportMenu(el, browser, operable);
|
|
156
|
+
renderBrowserSettings();
|
|
149
157
|
renderBrowserActivity(el, browser, connected);
|
|
150
158
|
layoutMonitor();
|
|
151
159
|
}
|
|
@@ -163,6 +171,16 @@ function selectBrowserTab(id) {
|
|
|
163
171
|
setBrowserTab(browser);
|
|
164
172
|
send('view', { visible: desktop() && !document.hidden }); render();
|
|
165
173
|
}
|
|
174
|
+
export function openSharedBrowserAt(value) {
|
|
175
|
+
var url = browserLinkTarget('browser:' + value);
|
|
176
|
+
if (!url) throw new Error('Enter a valid HTTP or HTTPS browser address.');
|
|
177
|
+
if (!desktop()) throw new Error('Clay Browser is available on desktop screens.');
|
|
178
|
+
if (!eligible()) throw new Error('Browser access is unavailable in this conversation.');
|
|
179
|
+
if (!store.get('connected')) throw new Error('Reconnect before opening this browser link.');
|
|
180
|
+
ensurePanel(); closeBrowserSettings(false);
|
|
181
|
+
claimRightWorkbench('browser'); store.set({ sharedBrowserOpen: true });
|
|
182
|
+
ui({ error: '' }); send('open', { url: url }); render();
|
|
183
|
+
}
|
|
166
184
|
export function openSharedBrowser() {
|
|
167
185
|
if (!eligible() || !store.get('connected')) return;
|
|
168
186
|
ensurePanel();
|
|
@@ -175,6 +193,7 @@ export function openSharedBrowser() {
|
|
|
175
193
|
}
|
|
176
194
|
export function hideSharedBrowser() {
|
|
177
195
|
closeViewportMenu();
|
|
196
|
+
closeBrowserSettings();
|
|
178
197
|
clearBrowserInput();
|
|
179
198
|
if (store.get('sharedBrowserOpen')) send('view', { visible: false });
|
|
180
199
|
store.set({ sharedBrowserOpen: false });
|
|
@@ -184,6 +203,7 @@ export function hideSharedBrowser() {
|
|
|
184
203
|
export function handleSharedBrowserMessage(msg) {
|
|
185
204
|
if (!msg.type || msg.type.indexOf('shared_browser_') !== 0) return false;
|
|
186
205
|
if (String(msg.sessionId) !== String(store.get('activeSessionId'))) return true;
|
|
206
|
+
if (handleBrowserSettingsMessage(msg)) return true;
|
|
187
207
|
if (msg.type === 'shared_browser_state') {
|
|
188
208
|
var old = store.get('sharedBrowser');
|
|
189
209
|
var tabs = msg.browsers || (msg.browser ? [msg.browser] : []);
|
|
@@ -217,6 +237,7 @@ export function handleSharedBrowserMessage(msg) {
|
|
|
217
237
|
return true;
|
|
218
238
|
}
|
|
219
239
|
export function initSharedBrowser() {
|
|
240
|
+
initBrowserLinks();
|
|
220
241
|
var button = document.getElementById('shared-browser-btn');
|
|
221
242
|
if (button) button.onclick = openSharedBrowser;
|
|
222
243
|
var toggle = document.getElementById('shared-browser-toggle-btn');
|
|
@@ -233,7 +254,7 @@ registerRightWorkbench('browser', hideSharedBrowser);
|
|
|
233
254
|
store.subscribe(function (state, previous) {
|
|
234
255
|
if (state.currentSlug !== previous.currentSlug || state.activeSessionId !== previous.activeSessionId || state.myUserId !== previous.myUserId) {
|
|
235
256
|
clearBrowserInput(); releaseRightWorkbench('browser');
|
|
236
|
-
store.set({ sharedBrowser: null, sharedBrowsers: [], sharedBrowserOpen: false, sharedBrowserUi: {} });
|
|
257
|
+
store.set({ sharedBrowser: null, sharedBrowsers: [], sharedBrowserOpen: false, sharedBrowserUi: {}, sharedBrowserSettings: {} });
|
|
237
258
|
if (state.connected) send('state_request');
|
|
238
259
|
render();
|
|
239
260
|
} else if (state.connected !== previous.connected) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { handlePaneBrowserMessage } from './pane-browser-bridge.js';
|
|
1
2
|
import { openWireframe } from './wireframe-workbench.js';
|
|
2
3
|
// Two-pane iframe shell for the split-view spike.
|
|
3
4
|
|
|
@@ -168,6 +169,7 @@ function handlePaneMessage(event) {
|
|
|
168
169
|
return;
|
|
169
170
|
}
|
|
170
171
|
if (handlePaneIssueMessage(event, host)) return;
|
|
172
|
+
if (handlePaneBrowserMessage(event, host)) return;
|
|
171
173
|
if (handlePaneFileMessage(event, host, openFile, revealFilesPanel)) return;
|
|
172
174
|
if (msg.type !== "clay-pane-context") return;
|
|
173
175
|
var frames = host.querySelectorAll(".split-pane-frame");
|
|
@@ -614,7 +614,14 @@ function rebuildPicker() {
|
|
|
614
614
|
|
|
615
615
|
// --- Init ---
|
|
616
616
|
export function initTheme() {
|
|
617
|
-
|
|
617
|
+
var seed = window.__clayAppearanceSeed;
|
|
618
|
+
if (seed && seed.configured) store.set({ appearancePreference: seed });
|
|
619
|
+
var initialMode = seed && seed.configured && (seed.mode === 'light' || seed.mode === 'dark')
|
|
620
|
+
? seed.mode
|
|
621
|
+
: getSystemMode();
|
|
622
|
+
currentThemeId = seed && seed.configured && seed[initialMode + 'Theme']
|
|
623
|
+
? seed[initialMode + 'Theme']
|
|
624
|
+
: (initialMode === 'light' ? DEFAULT_LIGHT_THEME_ID : DEFAULT_DARK_THEME_ID);
|
|
618
625
|
document.body.classList.toggle('wide-view', isWideView());
|
|
619
626
|
|
|
620
627
|
// Load all themes from server, then apply properly
|
|
@@ -244,6 +244,7 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
244
244
|
|
|
245
245
|
var container = document.createElement("div");
|
|
246
246
|
container.className = "ask-user-container";
|
|
247
|
+
if (input.source === "mcp-import") container.classList.add("mcp-import-consent");
|
|
247
248
|
container.dataset.toolId = toolId;
|
|
248
249
|
var requestKey = getAskUserRequestKey(toolId);
|
|
249
250
|
container.dataset.askUserRequestKey = requestKey;
|
|
@@ -364,7 +365,7 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
364
365
|
}
|
|
365
366
|
});
|
|
366
367
|
otherDiv.appendChild(otherInput);
|
|
367
|
-
qDiv.appendChild(otherDiv);
|
|
368
|
+
if (q.allowOther !== false || !(q.options || []).length) qDiv.appendChild(otherDiv);
|
|
368
369
|
container.appendChild(qDiv);
|
|
369
370
|
});
|
|
370
371
|
|
package/lib/public/style.css
CHANGED
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
@import url("css/home-debate-planning.css");
|
|
60
60
|
@import url("css/home-mate-creation.css");
|
|
61
61
|
@import url("css/home-mate-settings.css");
|
|
62
|
+
@import url("css/mate-avatar-gallery.css");
|
|
62
63
|
@import url("css/home-mate-model-picker.css");
|
|
63
64
|
@import url("css/project-mate-creation.css");
|
|
64
65
|
@import url("css/home-debate-live.css");
|
package/lib/public/sw.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var CACHE_NAME = "clay-offline-
|
|
1
|
+
var CACHE_NAME = "clay-offline-v5";
|
|
2
2
|
|
|
3
3
|
self.addEventListener("install", function (event) {
|
|
4
4
|
event.waitUntil(self.skipWaiting());
|
|
@@ -23,6 +23,8 @@ self.addEventListener("activate", function (event) {
|
|
|
23
23
|
function shouldCache(request, response) {
|
|
24
24
|
if (request.method !== "GET") return false;
|
|
25
25
|
if (!response || !response.ok) return false;
|
|
26
|
+
var cacheControl = response.headers && response.headers.get("Cache-Control") || "";
|
|
27
|
+
if (/(^|,)\s*(private|no-store)(?:\s*=\s*[^,]*)?(?=\s*(?:,|$))/i.test(cacheControl)) return false;
|
|
26
28
|
// Cache same-origin static assets and CDN resources (jsdelivr, fonts)
|
|
27
29
|
var url = new URL(request.url);
|
|
28
30
|
if (url.origin === self.location.origin) return true;
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -1812,7 +1812,7 @@ function createSDKBridge(opts) {
|
|
|
1812
1812
|
}
|
|
1813
1813
|
var hasSharedBrowserCatalog = sessionToolDefs.some(function (definition) { return definition.name === "shared_browser"; });
|
|
1814
1814
|
var recoverCodexBrowserTools = sessionAdapter.vendor === "codex" && !!session.cliSessionId
|
|
1815
|
-
&& hasSharedBrowserCatalog && Number(session.codexSharedBrowserToolCatalogVersion || 0) <
|
|
1815
|
+
&& hasSharedBrowserCatalog && Number(session.codexSharedBrowserToolCatalogVersion || 0) < 6;
|
|
1816
1816
|
var recoverCodexIssueTools = sessionAdapter.vendor === "codex"
|
|
1817
1817
|
&& !!session.cliSessionId
|
|
1818
1818
|
&& hasIssueCatalog
|
|
@@ -1931,6 +1931,12 @@ function createSDKBridge(opts) {
|
|
|
1931
1931
|
return snapshotDef;
|
|
1932
1932
|
}
|
|
1933
1933
|
|
|
1934
|
+
var externalQueryBridge = require('./mcp-query-bridge').createQueryBridge({ valid: queryContextAvailable,
|
|
1935
|
+
getServers: function () { return getRemoteMcpServers ? getRemoteMcpServers(session) || {} : {}; } });
|
|
1936
|
+
var externalToolDefs = sessionAdapter.vendor === 'codex' ? externalQueryBridge.dynamicDefs() : [];
|
|
1937
|
+
if (externalToolDefs.length) { sessionToolDefs = sessionToolDefs.concat(externalToolDefs); queryToolSnapshots.set(session, { generation: queryGeneration, defs: sessionToolDefs.slice() }); }
|
|
1938
|
+
var recoverCodexExternalTools = sessionAdapter.vendor === 'codex' && !!session.cliSessionId && (externalToolDefs.length > 0 || isMate);
|
|
1939
|
+
|
|
1934
1940
|
// Give fresh queries an immediate provisional label. The visible user
|
|
1935
1941
|
// message in history wins over `text`, which may contain an internal
|
|
1936
1942
|
// provider wrapper rather than what the person typed.
|
|
@@ -1986,7 +1992,7 @@ function createSDKBridge(opts) {
|
|
|
1986
1992
|
dynamicTools: sessionToolDefs,
|
|
1987
1993
|
// Codex persists dynamic tools with a thread. A stale authorized Driver
|
|
1988
1994
|
// gets this exact-query bridge; its handlers still reauthorize live.
|
|
1989
|
-
sessionMcpServer: (recoverCodexIssueTools || recoverCodexQuestionTools || recoverCodexBrowserTools || recoverCodexLinearTools || recoverCodexYouTools) ? getCodexSessionMcpServer(session, queryGeneration) : undefined,
|
|
1995
|
+
sessionMcpServer: (recoverCodexIssueTools || recoverCodexQuestionTools || recoverCodexBrowserTools || recoverCodexLinearTools || recoverCodexYouTools || recoverCodexExternalTools) ? getCodexSessionMcpServer(session, queryGeneration) : undefined,
|
|
1990
1996
|
callDynamicTool: function (toolName, args) {
|
|
1991
1997
|
var toolDef = findSessionToolDef(toolName);
|
|
1992
1998
|
if (toolDef && typeof toolDef.handler === "function") {
|
|
@@ -2208,7 +2214,7 @@ function createSDKBridge(opts) {
|
|
|
2208
2214
|
if (hasYouCatalog) codexCatalogCandidate = Object.assign({}, codexCatalogCandidate || {}, { generation: queryGeneration, youVersion: 1 });
|
|
2209
2215
|
if (hasLinearCatalog) codexCatalogCandidate = Object.assign({}, codexCatalogCandidate || {}, { generation: queryGeneration, linearVersion: 1 });
|
|
2210
2216
|
if (hasSharedBrowserCatalog) {
|
|
2211
|
-
codexCatalogCandidate = Object.assign({}, codexCatalogCandidate || {}, { generation: queryGeneration, sharedBrowserVersion:
|
|
2217
|
+
codexCatalogCandidate = Object.assign({}, codexCatalogCandidate || {}, { generation: queryGeneration, sharedBrowserVersion: 6 });
|
|
2212
2218
|
}
|
|
2213
2219
|
if (hasIssueCatalog) {
|
|
2214
2220
|
codexCatalogCandidate = Object.assign({}, codexCatalogCandidate || {}, {
|
|
@@ -34,6 +34,18 @@ function attachAppearanceSettings(ctx) {
|
|
|
34
34
|
fs.renameSync(defaultPath + '.tmp', defaultPath);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
function getInitialAppearance(req) {
|
|
38
|
+
var user = identity(req);
|
|
39
|
+
if (!user) return null;
|
|
40
|
+
var saved = read(user);
|
|
41
|
+
return {
|
|
42
|
+
configured: saved.configured,
|
|
43
|
+
theme: saved.theme,
|
|
44
|
+
mode: saved.mode,
|
|
45
|
+
lightTheme: saved.lightTheme || null,
|
|
46
|
+
darkTheme: saved.darkTheme || null
|
|
47
|
+
};
|
|
48
|
+
}
|
|
37
49
|
function handleRequest(req, res, url) {
|
|
38
50
|
if (url !== '/api/user/appearance') return false;
|
|
39
51
|
var user = identity(req);
|
|
@@ -66,6 +78,6 @@ function attachAppearanceSettings(ctx) {
|
|
|
66
78
|
});
|
|
67
79
|
return true;
|
|
68
80
|
}
|
|
69
|
-
return { handleRequest: handleRequest };
|
|
81
|
+
return { handleRequest: handleRequest, getInitialAppearance: getInitialAppearance };
|
|
70
82
|
}
|
|
71
83
|
module.exports = { attachAppearanceSettings: attachAppearanceSettings };
|
package/lib/server-dm.js
CHANGED
|
@@ -69,6 +69,7 @@ function attachDm(ctx) {
|
|
|
69
69
|
id: mate.id,
|
|
70
70
|
displayName: mp.displayName || mate.name || "New Mate",
|
|
71
71
|
username: mate.id,
|
|
72
|
+
avatarCatalogId: mp.avatarCatalogId || "",
|
|
72
73
|
avatarStyle: mp.avatarStyle || "imprint",
|
|
73
74
|
avatarSeed: mp.avatarSeed || mate.id,
|
|
74
75
|
avatarColor: mp.avatarColor || "#5857fc",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
function homeDebateQuestions(input) {
|
|
4
4
|
var source = input && Array.isArray(input.questions) && input.questions[0] ? input.questions[0] : null;
|
|
5
5
|
if (!source) return [];
|
|
6
|
-
var question = { header: source.header || "", question: source.question || "", multiSelect: false, options: [] };
|
|
6
|
+
var question = { header: source.header || "", question: source.question || "", multiSelect: false, allowOther: source.allowOther !== false, options: [] };
|
|
7
7
|
var options = Array.isArray(source.options) ? source.options.slice(0, 6) : [];
|
|
8
8
|
for (var i = 0; i < options.length; i++) question.options.push({ label: options[i].label || "Option", description: options[i].description || "" });
|
|
9
9
|
return [question];
|
|
@@ -36,6 +36,7 @@ function findDebateTurn(messages, event) {
|
|
|
36
36
|
function debateIdentity(source, fallback) {
|
|
37
37
|
var prior = fallback || {};
|
|
38
38
|
return {
|
|
39
|
+
avatarCatalogId: source.avatarCatalogId || prior.avatarCatalogId || "",
|
|
39
40
|
avatarStyle: source.avatarStyle || prior.avatarStyle || "imprint",
|
|
40
41
|
avatarSeed: source.avatarSeed || prior.avatarSeed || source.mateId || "mate",
|
|
41
42
|
avatarColor: source.avatarColor || prior.avatarColor || "",
|
|
@@ -112,7 +113,7 @@ function applyAssignmentHistoryEvent(messages, event) {
|
|
|
112
113
|
messages.push({ role: "assignment", assignment: assignment });
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
|
|
116
|
+
function historyToHomeChat(history, debateSetupMode, mateCreationMode, pendingAskUser) {
|
|
116
117
|
var messages = [];
|
|
117
118
|
var pending = "";
|
|
118
119
|
var interviewMode = debateSetupMode === true || mateCreationMode === true;
|
|
@@ -124,6 +125,12 @@ function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
|
|
|
124
125
|
for (var i = 0; i < history.length; i++) {
|
|
125
126
|
var event = history[i];
|
|
126
127
|
if (!event) continue;
|
|
128
|
+
if (event.type === 'tool_executing' && event.name === 'AskUserQuestion' && event.source === 'mcp-import') {
|
|
129
|
+
flushAssistant();
|
|
130
|
+
var activeConsent = pendingAskUser === undefined || !!(pendingAskUser && pendingAskUser[event.id]);
|
|
131
|
+
messages.push({ role: 'question', flow: 'mcp_import', toolId: event.id, questions: homeDebateQuestions(event.input), status: activeConsent ? 'pending' : 'expired', error: activeConsent ? '' : 'This import consent is no longer active. Ask for a new scan and review.' });
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
127
134
|
if (event.type === "project_assignment_proposal" || event.type === "project_assignment_status") {
|
|
128
135
|
flushAssistant();
|
|
129
136
|
applyAssignmentHistoryEvent(messages, event);
|
|
@@ -185,7 +192,7 @@ function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
|
|
|
185
192
|
} else if (interviewMode && event.type === "tool_executing" && event.name === "AskUserQuestion" && event.id && event.input) {
|
|
186
193
|
flushAssistant();
|
|
187
194
|
messages.push({ role: "question", flow: mateCreationMode === true ? "mate_creation" : "debate", toolId: event.id, questions: homeDebateQuestions(event.input), status: "pending", error: "" });
|
|
188
|
-
} else if ((event.type === "ask_user_answered" || event.type === "home_debate_question_expired" || event.type === "home_mate_creation_question_expired") && event.toolId) {
|
|
195
|
+
} else if ((event.type === "ask_user_answered" || event.type === "home_debate_question_expired" || event.type === "home_mate_creation_question_expired" || event.type === "mcp_import_consent_expired") && event.toolId) {
|
|
189
196
|
for (var k = messages.length - 1; k >= 0; k--) {
|
|
190
197
|
if (messages[k].role === "question" && messages[k].toolId === event.toolId) {
|
|
191
198
|
messages[k].status = event.type === "ask_user_answered" ? "answered" : "expired";
|
|
@@ -273,7 +280,7 @@ function transformEvent(event, mateId, session, requestId, stableSessionId) {
|
|
|
273
280
|
}
|
|
274
281
|
if (session && session.homeDebatePlanning === true && HOME_DEBATE_EVENT_TYPES[event.type]) {
|
|
275
282
|
var live = { type: "home_debate_event", eventType: event.type };
|
|
276
|
-
var fields = ["turnId", "decisionId", "decision", "toolName", "command", "commandTruncated", "topic", "format", "moderatorId", "moderatorName", "panelists", "mateName", "role", "round", "activity", "delta", "text", "reason", "action", "avatarStyle", "avatarSeed", "avatarColor", "avatarCustom"];
|
|
283
|
+
var fields = ["turnId", "decisionId", "decision", "toolName", "command", "commandTruncated", "topic", "format", "moderatorId", "moderatorName", "panelists", "mateName", "role", "round", "activity", "delta", "text", "reason", "action", "avatarCatalogId", "avatarStyle", "avatarSeed", "avatarColor", "avatarCustom"];
|
|
277
284
|
for (var fi = 0; fi < fields.length; fi++) if (Object.prototype.hasOwnProperty.call(event, fields[fi])) live[fields[fi]] = event[fields[fi]];
|
|
278
285
|
if (event.mateId) live.speakerMateId = event.mateId;
|
|
279
286
|
return Object.assign(live, metadata);
|
|
@@ -298,6 +305,9 @@ function transformEvent(event, mateId, session, requestId, stableSessionId) {
|
|
|
298
305
|
if (event.type === "debate_proposal_resolved" && event.proposalId) return Object.assign({ type: "home_debate_proposal_resolved", proposalId: event.proposalId, action: event.action || "cancel", error: event.error || "" }, metadata);
|
|
299
306
|
if (session && session.mateCreationMode === true && event.type === "mate_creation_proposal" && event.proposal) return Object.assign({ type: "home_mate_creation_proposal", proposal: event.proposal }, metadata);
|
|
300
307
|
if (session && session.mateCreationMode === true && event.type === "mate_creation_proposal_resolved" && event.proposalId) return Object.assign({ type: "home_mate_creation_proposal_resolved", proposalId: event.proposalId, action: event.action || "cancel", createdMateId: event.mateId || null, mateName: event.mateName || null, error: event.error || "" }, metadata);
|
|
308
|
+
if (event.type === 'tool_executing' && event.name === 'AskUserQuestion' && event.source === 'mcp-import') return Object.assign({ type: 'home_mcp_import_question', toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
|
|
309
|
+
if (event.type === 'mcp_import_consent_expired') return Object.assign({ type: 'home_mcp_import_question_resolved', toolId: event.toolId, status: 'expired', error: event.error }, metadata);
|
|
310
|
+
if (session && event.type === 'ask_user_answered' && event.toolId && (session.history || []).some(function (item) { return item.id === event.toolId && item.source === 'mcp-import'; })) return Object.assign({ type: 'home_mcp_import_question_resolved', toolId: event.toolId, status: 'answered', answers: event.answers }, metadata);
|
|
301
311
|
if (session && session.debateSetupMode === true && event.type === "tool_executing" && event.name === "AskUserQuestion" && event.id && event.input) {
|
|
302
312
|
return Object.assign({ type: "home_debate_question", toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
|
|
303
313
|
}
|
package/lib/server-home-chat.js
CHANGED
|
@@ -184,6 +184,12 @@ function attachHomeChat(deps) {
|
|
|
184
184
|
}
|
|
185
185
|
});
|
|
186
186
|
if (!unsubscribe) return;
|
|
187
|
+
var unregisterConsent = null;
|
|
188
|
+
if (openedSession && typeof found.ctx.registerMcpConsentViewer === 'function') {
|
|
189
|
+
try { unregisterConsent = found.ctx.registerMcpConsentViewer(ws, openedSession); } catch (error) {}
|
|
190
|
+
}
|
|
191
|
+
var unsubscribeEvents = unsubscribe;
|
|
192
|
+
unsubscribe = function () { if (unregisterConsent) unregisterConsent(); unsubscribeEvents(); };
|
|
187
193
|
ws[tapKey] = {
|
|
188
194
|
unsubscribe: unsubscribe,
|
|
189
195
|
sessionId: sessionId,
|
|
@@ -238,7 +244,7 @@ function attachHomeChat(deps) {
|
|
|
238
244
|
requestId: requestId || null,
|
|
239
245
|
model: session.model || null,
|
|
240
246
|
vendor: session.vendor || null,
|
|
241
|
-
messages: historyToHomeChat(session.history || [], session.debateSetupMode === true, session.mateCreationMode === true),
|
|
247
|
+
messages: historyToHomeChat(session.history || [], session.debateSetupMode === true, session.mateCreationMode === true, session.pendingAskUser),
|
|
242
248
|
isProcessing: session.isProcessing === true,
|
|
243
249
|
};
|
|
244
250
|
if (session.homeClayEntryMode === "search") {
|
|
@@ -293,6 +299,7 @@ function attachHomeChat(deps) {
|
|
|
293
299
|
homeModels: homeModels, isActorLive: isActorLive, persistActiveSession: persistActiveSession,
|
|
294
300
|
});
|
|
295
301
|
var homeMateCreation = attachHomeMateCreation({ findMateProject: findMateProject, resolveHomeSession: resolveHomeSession, sessionReference: sessionReference, setupTap: setupTap, sendHistory: sendHistory, sendSessionList: sendSessionList, sendError: sendError, sendModelError: sendModelError, homeModels: homeModels, isActorLive: isActorLive, persistActiveSession: persistActiveSession });
|
|
302
|
+
var homeMcpConsent = require('./server-home-mcp-consent').attachHomeMcpConsent({ findMateProject: findMateProject, resolveHomeSession: resolveHomeSession, messageTap: messageTap, isActorLive: isActorLive, sendError: sendError });
|
|
296
303
|
var homeClayEntry = attachHomeClayEntry({ findMateProject: findMateProject, ownsSession: ownsSession, sessionReference: sessionReference, setupSearchTap: setupSearchTap, sendHistory: sendHistory, sendSessionList: sendSessionList, sendError: sendError, sendModelError: sendModelError, homeModels: homeModels, isActorLive: isActorLive });
|
|
297
304
|
|
|
298
305
|
async function openExactSession(ws, found, userId, selected, msg) {
|
|
@@ -449,7 +456,7 @@ function attachHomeChat(deps) {
|
|
|
449
456
|
}
|
|
450
457
|
return true;
|
|
451
458
|
}
|
|
452
|
-
if (msg.type !== "issue_reference_resolve" && msg.type !== "home_debates_list" && msg.type !== "home_clay_ask" && msg.type !== "home_clay_session_resolve" && msg.type !== "home_clay_log_resolve" && msg.type !== "home_mate_present" && msg.type !== "home_mate_open" && msg.type !== "home_mate_sessions_list" && msg.type !== "home_mate_session_open" && msg.type !== "home_mate_send" && msg.type !== "home_mate_new_session" && msg.type !== "home_mate_debate_plan" && msg.type !== "home_debate_proposal_response" && msg.type !== "home_debate_question_response" && msg.type !== "home_debate_control" && msg.type !== "home_mate_creation_plan" && msg.type !== "home_mate_creation_question_response" && msg.type !== "home_mate_creation_proposal_response" && msg.type !== "home_mate_close" && msg.type !== "home_mate_memory_list" && msg.type !== "home_mate_knowledge_list" && msg.type !== "home_mate_models_get" && msg.type !== "home_mate_model_set") {
|
|
459
|
+
if (msg.type !== "issue_reference_resolve" && msg.type !== "home_debates_list" && msg.type !== "home_clay_ask" && msg.type !== "home_clay_session_resolve" && msg.type !== "home_clay_log_resolve" && msg.type !== "home_mate_present" && msg.type !== "home_mate_open" && msg.type !== "home_mate_sessions_list" && msg.type !== "home_mate_session_open" && msg.type !== "home_mate_send" && msg.type !== "home_mate_new_session" && msg.type !== "home_mate_debate_plan" && msg.type !== "home_debate_proposal_response" && msg.type !== "home_mcp_import_response" && msg.type !== "home_debate_question_response" && msg.type !== "home_debate_control" && msg.type !== "home_mate_creation_plan" && msg.type !== "home_mate_creation_question_response" && msg.type !== "home_mate_creation_proposal_response" && msg.type !== "home_mate_close" && msg.type !== "home_mate_memory_list" && msg.type !== "home_mate_knowledge_list" && msg.type !== "home_mate_models_get" && msg.type !== "home_mate_model_set") {
|
|
453
460
|
return false;
|
|
454
461
|
}
|
|
455
462
|
|
|
@@ -474,6 +481,7 @@ function attachHomeChat(deps) {
|
|
|
474
481
|
return true;
|
|
475
482
|
}
|
|
476
483
|
|
|
484
|
+
if (msg.type === "home_mcp_import_response") { homeMcpConsent.respond(ws, userId, msg); return true; }
|
|
477
485
|
if (msg.type === "issue_reference_resolve") { resolveIssueLink(ws, msg); return true; }
|
|
478
486
|
if (homeDebates.handle(ws, userId, msg)) return true;
|
|
479
487
|
if (msg.type === "home_clay_ask") { homeClayEntry.start(ws, userId, msg); return true; }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Home transcript responses retain the project's server-owned consent request.
|
|
2
|
+
function attachHomeMcpConsent(ctx) {
|
|
3
|
+
function respond(ws, userId, msg) {
|
|
4
|
+
var found = ctx.findMateProject(userId, msg.mateId || null, false);
|
|
5
|
+
var session = found && ctx.resolveHomeSession(found, userId, msg.sessionId);
|
|
6
|
+
var tap = ctx.messageTap(ws, msg), pending = session && session.pendingAskUser && session.pendingAskUser[msg.toolId];
|
|
7
|
+
if (!ctx.isActorLive(ws, userId) || !found || !session || !tap || tap.mateSlug !== found.slug || tap.sessionId !== session.localId || (tap.requestId || null) !== (msg.requestId || null) || !pending || !pending.request || pending.request.source !== 'mcp-import') {
|
|
8
|
+
ctx.sendError(ws, found && found.mate.id, 'This owner import consent is unavailable or expired.', msg.requestId || null, msg.sessionId || null, 'question_expired', { toolId: msg.toolId }); return;
|
|
9
|
+
}
|
|
10
|
+
if (!found.ctx.handleHomeAskUserResponse({ type: 'ask_user_response', toolId: msg.toolId, answers: msg.answers || {} }, session, ws)) ctx.sendError(ws, found.mate.id, 'This import consent could not be submitted. No import was authorized.', msg.requestId || null, msg.sessionId, 'question_refused', { toolId: msg.toolId });
|
|
11
|
+
}
|
|
12
|
+
return { respond: respond };
|
|
13
|
+
}
|
|
14
|
+
module.exports = { attachHomeMcpConsent: attachHomeMcpConsent };
|
package/lib/server-mates.js
CHANGED
|
@@ -304,7 +304,12 @@ function attachMates(ctx) {
|
|
|
304
304
|
return true;
|
|
305
305
|
}
|
|
306
306
|
var mateCtx7 = mates.buildMateCtx(userId);
|
|
307
|
-
var updated
|
|
307
|
+
var updated;
|
|
308
|
+
try { updated = mates.updateMate(mateCtx7, msg.mateId, msg.updates); }
|
|
309
|
+
catch (error) {
|
|
310
|
+
ws.send(JSON.stringify({ type: "mate_error", mateId: msg.mateId, requestId: msg.requestId, error: "Could not save this Mate. Your changes were not acknowledged; try again." }));
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
308
313
|
if (updated && updated.error) {
|
|
309
314
|
ws.send(JSON.stringify({ type: "mate_error", mateId: msg.mateId, requestId: msg.requestId, error: updated.error }));
|
|
310
315
|
return true;
|
package/lib/server-settings.js
CHANGED
|
@@ -755,7 +755,10 @@ function attachSettings(ctx) {
|
|
|
755
755
|
return false;
|
|
756
756
|
}
|
|
757
757
|
|
|
758
|
-
return {
|
|
758
|
+
return {
|
|
759
|
+
handleRequest: handleRequest,
|
|
760
|
+
getInitialAppearance: appearanceSettings.getInitialAppearance
|
|
761
|
+
};
|
|
759
762
|
}
|
|
760
763
|
|
|
761
764
|
module.exports = { attachSettings: attachSettings };
|