clay-server 4.8.0-beta.1 → 4.8.0-beta.2
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/bundled-skills/clay-agent-browser/SKILL.md +36 -0
- package/lib/clay-skill-install.js +33 -0
- package/lib/clay-skill-storage.js +49 -0
- package/lib/project-http.js +14 -5
- package/lib/project-shared-browser.js +256 -0
- package/lib/project.js +35 -1
- package/lib/public/app.js +7 -0
- package/lib/public/css/filebrowser.css +2 -25
- package/lib/public/css/issues.css +1 -14
- package/lib/public/css/mcp-skills-workbench.css +51 -0
- package/lib/public/css/project-logs.css +0 -11
- package/lib/public/css/right-workbench.css +28 -0
- package/lib/public/css/scheduled-tasks.css +1 -1
- package/lib/public/css/shared-browser-skins.css +28 -0
- package/lib/public/css/shared-browser.css +91 -0
- package/lib/public/css/sticky-notes.css +0 -11
- package/lib/public/index.html +30 -22
- package/lib/public/modules/app-messages.js +2 -0
- package/lib/public/modules/extension-settings.js +110 -0
- package/lib/public/modules/mcp-skills-workbench.js +67 -0
- package/lib/public/modules/mcp-ui.js +9 -12
- package/lib/public/modules/notifications.js +2 -107
- package/lib/public/modules/shared-browser-activity.js +66 -0
- package/lib/public/modules/shared-browser-input.js +73 -0
- package/lib/public/modules/shared-browser-tabs.js +33 -0
- package/lib/public/modules/shared-browser-viewport-menu.js +76 -0
- package/lib/public/modules/shared-browser.js +214 -0
- package/lib/public/modules/sidebar-mobile.js +3 -3
- package/lib/public/modules/skills-actions.js +247 -0
- package/lib/public/modules/skills-detail.js +148 -0
- package/lib/public/modules/skills-state.js +10 -0
- package/lib/public/modules/skills.js +64 -459
- package/lib/public/modules/tool-palette-order.js +11 -13
- package/lib/public/style.css +6 -0
- package/lib/sdk-bridge.js +14 -1
- package/lib/sessions.js +2 -0
- package/lib/shared-browser-activity-history.js +17 -0
- package/lib/shared-browser-policy.js +26 -0
- package/lib/shared-browser-runtime.js +82 -0
- package/lib/shared-browser-tools.js +21 -0
- package/lib/shared-browser-worker.js +160 -0
- package/lib/ws-schema.js +10 -0
- package/lib/yoke/skill-discovery.js +22 -2
- package/package.json +1 -1
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
#issues-panel { position: relative; width: 50%; max-width: 720px; min-width: 360px; height: calc(100% - 16px); margin: 8px 8px 8px 10px; min-height: 0; align-self: center; display: flex; flex-direction: column; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; flex-shrink: 0; }
|
|
2
|
-
@media (min-width: 1024px) {
|
|
3
|
-
#issues-panel {
|
|
4
|
-
box-shadow:
|
|
5
|
-
4px 8px 18px rgba(var(--shadow-rgb), 0.14),
|
|
6
|
-
2px 2px 4px rgba(var(--shadow-rgb), 0.08),
|
|
7
|
-
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
|
8
|
-
animation: workbench-panel-in 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
9
|
-
transition: max-width 0.2s ease, width 0.2s ease, box-shadow 0.2s ease;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
@media (prefers-reduced-motion: reduce) {
|
|
13
|
-
#issues-panel { animation: none; }
|
|
14
|
-
}
|
|
15
2
|
#issues-panel.hidden { display: none; }
|
|
16
3
|
#issues-panel.issues-wide { width: 70%; max-width: 1200px; }
|
|
17
|
-
#issues-panel.panel-fullscreen { width: 100%; max-width: none; min-width: 0; height: 100%; margin: 0; border: 0; border-radius: 0;
|
|
4
|
+
#issues-panel.panel-fullscreen { width: 100%; max-width: none; min-width: 0; height: 100%; margin: 0; border: 0; border-radius: 0; }
|
|
18
5
|
#issues-panel header { height: 48px; box-sizing: border-box; display: flex; align-items: center; gap: 12px; padding: 0 16px; border-bottom: 1px solid var(--border-subtle); flex: 0 0 auto; }
|
|
19
6
|
#issues-panel .issues-title { display: inline-flex; align-items: center; gap: 7px; font-weight: 700; }
|
|
20
7
|
#issues-panel .issues-title .lucide { width: 15px; color: var(--accent); }
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.mcp-skills-workbench { display:flex; flex-direction:column; flex-shrink:0; width:50%; max-width:720px; min-width:360px; height:calc(100% - 16px); align-self:center; margin:8px 8px 8px 10px; border:1px solid var(--border); border-radius:12px; background:var(--bg); overflow:hidden; }
|
|
2
|
+
.mcp-skills-workbench.hidden { display:none; }
|
|
3
|
+
.mcp-skills-workbench.workbench-wide { width:70%; max-width:1200px; }
|
|
4
|
+
.mcp-skills-workbench.panel-fullscreen { width:100%; max-width:none; min-width:0; height:100%; margin:0; border:0; border-radius:0; }
|
|
5
|
+
.mcp-skills-header { display:flex; align-items:center; justify-content:space-between; padding:12px 14px; border-bottom:1px solid var(--border); }
|
|
6
|
+
.mcp-skills-header strong,.mcp-skills-header>div { display:flex; align-items:center; gap:8px; font-size:12px; font-weight:600; }
|
|
7
|
+
.mcp-skills-header svg { width:15px; height:15px; }
|
|
8
|
+
.mcp-skills-header button { display:flex; padding:6px; background:transparent; border:0; border-radius:6px; color:var(--text-muted); cursor:pointer; }
|
|
9
|
+
.mcp-skills-header button:hover { background:var(--bg-alt); color:var(--text); }
|
|
10
|
+
.mcp-skills-tabs { display:flex; padding:0 16px; border-bottom:1px solid var(--border); gap:24px; flex-shrink:0; }
|
|
11
|
+
.mcp-skills-tabs button { padding:13px 0 11px; background:none; border:0; border-bottom:2px solid transparent; color:var(--text-muted); font:inherit; font-size:12px; cursor:pointer; }
|
|
12
|
+
.mcp-skills-tabs button[aria-selected="true"] { color:var(--text); border-bottom-color:var(--accent); }
|
|
13
|
+
.mcp-skills-tabs button[hidden] { display:none; }
|
|
14
|
+
#mcp-skills-workbench #skills-modal,#mcp-skills-workbench #mcp-modal { position:static; inset:auto; z-index:auto; display:flex; flex:1; min-height:0; align-items:stretch; justify-content:stretch; }
|
|
15
|
+
#mcp-skills-workbench #skills-modal.hidden,#mcp-skills-workbench #mcp-modal.hidden { display:none; }
|
|
16
|
+
#mcp-skills-workbench .skills-dialog,#mcp-skills-workbench .mcp-dialog { width:100%; max-width:none; min-width:0; height:100%; max-height:none; padding:0; display:flex; flex-direction:column; overflow:hidden; }
|
|
17
|
+
#mcp-skills-workbench .mcp-header,#mcp-skills-workbench #skills-modal-close { display:none; }
|
|
18
|
+
#mcp-skills-workbench .skills-header { padding:12px 16px 0; }
|
|
19
|
+
#mcp-skills-workbench .skills-title { font-size:12px; font-weight:500; }
|
|
20
|
+
#mcp-skills-workbench .skills-powered-by { font-size:10px; }
|
|
21
|
+
#mcp-skills-workbench .skills-search { margin:12px 16px 0; }
|
|
22
|
+
#mcp-skills-workbench .skills-tabs { padding:8px 16px 0; gap:0; overflow-x:auto; }
|
|
23
|
+
#mcp-skills-workbench .skills-tab { padding:9px 10px; font-size:11px; white-space:nowrap; }
|
|
24
|
+
#mcp-skills-workbench .skills-content,#mcp-skills-workbench .mcp-content { flex:1; min-height:0; overflow-y:auto; padding:16px; }
|
|
25
|
+
#mcp-skills-workbench .skills-detail { display:flex; flex-direction:column; gap:24px; height:auto; min-height:0; }
|
|
26
|
+
#mcp-skills-workbench .skills-detail-main { min-width:0; flex:none; border-right:0; overflow:visible; }
|
|
27
|
+
#mcp-skills-workbench .skills-detail-sidebar { width:auto; border-left:0; padding-left:0; border-top:1px solid var(--border); padding-top:20px; }
|
|
28
|
+
#mcp-skills-workbench .skills-detail-name { font-size:24px; overflow-wrap:anywhere; }
|
|
29
|
+
#mcp-skills-workbench .skills-installed-item { align-items:flex-start; }
|
|
30
|
+
#mcp-skills-workbench .skills-item { padding:12px 0; }
|
|
31
|
+
#mcp-skills-workbench .mcp-server-row { flex-wrap:wrap; }
|
|
32
|
+
#mcp-skills-workbench .mcp-server-perm-reason { flex-basis:100%; padding-left:26px; }
|
|
33
|
+
#mcp-skills-workbench button:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
|
|
34
|
+
@media (max-width:1023px) { .mcp-skills-workbench,.mcp-skills-workbench.workbench-wide { position:fixed; inset:0; z-index:160; width:100%; max-width:none; min-width:0; height:100dvh; margin:0; border:0; border-radius:0; padding-top:env(safe-area-inset-top); padding-bottom:env(safe-area-inset-bottom); } }
|
|
35
|
+
|
|
36
|
+
#mcp-skills-workbench .skills-detail-main > .skills-detail-md-wrap { flex:none; overflow:visible; padding:0; }
|
|
37
|
+
#mcp-skills-workbench .skills-detail-main > .skills-detail-name,#mcp-skills-workbench .skills-detail-main > .skills-detail-desc,#mcp-skills-workbench .skills-detail-main > .skills-detail-cmd { margin-left:0; margin-right:0; }
|
|
38
|
+
|
|
39
|
+
#mcp-skills-workbench .skills-detail-cmd code { min-width:0; overflow-x:auto; }
|
|
40
|
+
|
|
41
|
+
#mcp-skills-workbench .ext-pill-wrap { display:block; flex-shrink:0; padding:12px 16px; border-bottom:1px solid var(--border); max-height:55%; overflow-y:auto; }
|
|
42
|
+
#mcp-skills-workbench .top-bar-ext-btn { padding:8px 10px; border-radius:6px; gap:6px; }
|
|
43
|
+
#mcp-skills-workbench .top-bar-ext-btn::after { content:"Setup"; margin-left:8px; color:var(--text-muted); font-weight:400; }
|
|
44
|
+
#mcp-skills-workbench .top-bar-ext-btn.ext-connected::after { content:"Connected"; color:var(--success); }
|
|
45
|
+
#mcp-skills-workbench .ext-popover { position:static; width:auto; margin-top:12px; padding:12px; box-shadow:none; border-radius:8px; }
|
|
46
|
+
|
|
47
|
+
#mcp-skills-workbench .ext-feature-summary { margin:8px 0 0; font-size:12px; line-height:1.5; color:var(--text-muted); }
|
|
48
|
+
#mcp-skills-workbench .ext-popover-desc p { margin:0 0 8px; }
|
|
49
|
+
#mcp-skills-workbench .ext-feature-list { margin:0 0 16px; padding-left:18px; }
|
|
50
|
+
#mcp-skills-workbench .ext-feature-list li { margin-bottom:8px; line-height:1.6; }
|
|
51
|
+
#mcp-skills-workbench .ext-feature-list strong { color:var(--text); font-weight:500; }
|
|
@@ -18,12 +18,6 @@
|
|
|
18
18
|
flex-direction: column;
|
|
19
19
|
overflow: hidden;
|
|
20
20
|
flex-shrink: 0;
|
|
21
|
-
box-shadow:
|
|
22
|
-
4px 8px 18px rgba(var(--shadow-rgb), 0.14),
|
|
23
|
-
2px 2px 4px rgba(var(--shadow-rgb), 0.08),
|
|
24
|
-
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
|
25
|
-
animation: workbench-panel-in 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
26
|
-
transition: max-width 0.2s ease, width 0.2s ease, box-shadow 0.2s ease;
|
|
27
21
|
}
|
|
28
22
|
#project-logs-panel.hidden { display: none; }
|
|
29
23
|
#project-logs-panel.project-logs-wide {
|
|
@@ -38,14 +32,9 @@
|
|
|
38
32
|
margin: 0;
|
|
39
33
|
border: 0;
|
|
40
34
|
border-radius: 0;
|
|
41
|
-
box-shadow: none;
|
|
42
|
-
animation: none;
|
|
43
35
|
}
|
|
44
36
|
}
|
|
45
37
|
|
|
46
|
-
@media (prefers-reduced-motion: reduce) {
|
|
47
|
-
#project-logs-panel { animation: none; }
|
|
48
|
-
}
|
|
49
38
|
|
|
50
39
|
/* Narrow screens: full overlay, like the other workbench tools. */
|
|
51
40
|
@media (max-width: 1023px) {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* Shared desktop workbench elevation and motion. Keep panel content styles local. */
|
|
2
|
+
@keyframes workbench-panel-in {
|
|
3
|
+
from { opacity: 0; transform: translateX(10px) scale(0.995); }
|
|
4
|
+
to { opacity: 1; transform: translateX(0) scale(1); }
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@media (min-width: 1024px) {
|
|
8
|
+
:is(#file-viewer, #terminal-container, #project-logs-panel, #issues-panel, #notes-browser, #scheduled-tasks-panel, #shared-browser-panel, #mcp-skills-workbench):not(.panel-fullscreen) {
|
|
9
|
+
box-shadow:
|
|
10
|
+
4px 8px 18px rgba(var(--shadow-rgb), 0.14),
|
|
11
|
+
2px 2px 4px rgba(var(--shadow-rgb), 0.08),
|
|
12
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
|
13
|
+
animation: workbench-panel-in 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
14
|
+
transition: max-width 0.2s ease, width 0.2s ease, box-shadow 0.2s ease;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:is(#file-viewer, #terminal-container, #project-logs-panel, #issues-panel, #notes-browser, #scheduled-tasks-panel, #shared-browser-panel, #mcp-skills-workbench).panel-fullscreen {
|
|
19
|
+
box-shadow: none;
|
|
20
|
+
animation: none;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@media (prefers-reduced-motion: reduce) {
|
|
24
|
+
:is(#file-viewer, #terminal-container, #project-logs-panel, #issues-panel, #notes-browser, #scheduled-tasks-panel, #shared-browser-panel, #mcp-skills-workbench):not(.panel-fullscreen) {
|
|
25
|
+
animation: none;
|
|
26
|
+
transition: none;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
@media (min-width: 1024px) {
|
|
2
|
-
#scheduled-tasks-panel { width: 50%; max-width: 760px; min-width: 380px; height: calc(100% - 16px); min-height: 0; align-self: center; margin: 8px 8px 8px 10px; border: 1px solid var(--border); border-radius: 12px; background: var(--bg); display: flex; flex-direction: column; overflow: hidden; flex-shrink: 0;
|
|
2
|
+
#scheduled-tasks-panel { width: 50%; max-width: 760px; min-width: 380px; height: calc(100% - 16px); min-height: 0; align-self: center; margin: 8px 8px 8px 10px; border: 1px solid var(--border); border-radius: 12px; background: var(--bg); display: flex; flex-direction: column; overflow: hidden; flex-shrink: 0; }
|
|
3
3
|
#scheduled-tasks-panel.hidden { display: none; }
|
|
4
4
|
#scheduled-tasks-panel.scheduled-tasks-wide { width: 70%; max-width: 1200px; }
|
|
5
5
|
#scheduled-tasks-panel.panel-fullscreen { width: 100%; max-width: none; min-width: 0; height: 100%; margin: 0; border: 0; border-radius: 0; }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* Device silhouettes follow viewport dimensions; they do not emulate an OS. */
|
|
2
|
+
.shared-browser-viewport[data-skin="laptop"] .shared-browser-monitor { border: 9px solid #252729; border-bottom: 30px solid #c8cbcc; border-radius: 12px 12px 5px 5px; box-shadow: 0 0 0 2px #acb0b2, 0 20px 32px #0005; }
|
|
3
|
+
.shared-browser-viewport[data-skin="laptop"] .shared-browser-monitor-brand { left: 0; right: 0; text-align: center; color: #53585a; }
|
|
4
|
+
.shared-browser-viewport[data-skin="laptop"] .shared-browser-monitor-stand { bottom: -49px; height: 18px; width: calc(100% + 60px); background: linear-gradient(#dfe1e2, #babfc2); border-radius: 2px 2px 45% 45%; box-shadow: 0 3px 0 #858b8e, 0 12px 15px #0005; }
|
|
5
|
+
.shared-browser-viewport[data-skin="laptop"] .shared-browser-monitor-stand::before { top: 0; bottom: auto; height: 5px; left: 42%; right: 42%; clip-path: none; background: #9ba1a4; border-radius: 0 0 5px 5px; }
|
|
6
|
+
.shared-browser-viewport[data-skin="laptop"] .shared-browser-monitor-stand::after { display: none; }
|
|
7
|
+
.shared-browser-viewport[data-skin="crt"] { background: #183638; }
|
|
8
|
+
.shared-browser-viewport[data-skin="crt"] .shared-browser-monitor { border: 22px solid #c9c7b9; border-bottom-width: 42px; border-radius: 24px; box-shadow: inset 0 0 0 3px #797b72, 0 0 0 2px #e4e1d4, 8px 10px 0 #999b90, 12px 24px 30px #0005; }
|
|
9
|
+
.shared-browser-viewport[data-skin="crt"] .shared-browser-monitor::before { inset: -5px; border: 5px solid; border-color: #8a8b80 #b4b5a8 #e3e1d4 #9c9e91; border-radius: 6px; }
|
|
10
|
+
.shared-browser-viewport[data-skin="crt"] .shared-browser-monitor-brand { bottom: -33px; }
|
|
11
|
+
.shared-browser-viewport[data-skin="crt"] .shared-browser-monitor::after { bottom: -28px; right: 6px; width: 9px; height: 9px; border: 3px solid #afb1a3; }
|
|
12
|
+
.shared-browser-viewport[data-skin="crt"] .shared-browser-monitor-stand { bottom: -66px; width: 35%; height: 24px; }
|
|
13
|
+
.shared-browser-viewport[data-skin="crt"] .shared-browser-monitor-detail { position: absolute; bottom: -27px; right: 35px; width: 40px; height: 4px; background: repeating-linear-gradient(90deg, #85897e 0 6px, transparent 6px 12px); }
|
|
14
|
+
.shared-browser-viewport[data-skin="mac"] { background: #292824; gap: 28px; }
|
|
15
|
+
.shared-browser-viewport[data-skin="mac"] .shared-browser-monitor { border: 24px solid #d7cfbb; border-top-width: 30px; border-bottom-width: 78px; border-radius: 15px 15px 7px 7px; box-shadow: 0 5px 0 #afa68f, 0 7px 0 #e6ddc9, 0 22px 30px #0005; }
|
|
16
|
+
.shared-browser-viewport[data-skin="mac"] .shared-browser-monitor::before { inset: -6px; border: 6px solid; border-color: #aaa18c #bcb39d #ede4cf #bab099; border-radius: 9px; }
|
|
17
|
+
.shared-browser-viewport[data-skin="mac"] .shared-browser-monitor-brand { bottom: -51px; left: 1px; color: #696250; }
|
|
18
|
+
.shared-browser-viewport[data-skin="mac"] .shared-browser-monitor-stand { display: none; }
|
|
19
|
+
.shared-browser-viewport[data-skin="mac"] .shared-browser-monitor-detail { position: absolute; bottom: -43px; right: 2px; width: 30%; height: 5px; background: #625f54; border-bottom: 2px solid #efe6d3; border-radius: 1px; }
|
|
20
|
+
.shared-browser-viewport[data-skin="mac"] .shared-browser-monitor-detail::after { content: ""; position: absolute; top: 15px; right: 0; width: 65%; height: 10px; background: repeating-linear-gradient(90deg, #aaa08a 0 2px, transparent 2px 5px); }
|
|
21
|
+
.shared-browser-viewport[data-skin="mac"] .shared-browser-monitor::after { bottom: -67px; }
|
|
22
|
+
.shared-browser-viewport[data-skin="phone"] { background: #23282d; gap: 24px; }
|
|
23
|
+
.shared-browser-viewport[data-skin="phone"] .shared-browser-monitor { border: 12px solid #141517; border-top-width: 48px; border-bottom-width: 54px; border-radius: 38px; box-shadow: 0 0 0 2px #9a9d9f, 0 0 0 4px #46494c, 0 20px 35px #0006; }
|
|
24
|
+
.shared-browser-viewport[data-skin="phone"] .shared-browser-monitor::before { inset: auto auto -44px 50%; width: 32px; height: 32px; transform: translateX(-50%); border: 1px solid #666a6e; border-radius: 50%; background: #191b1d; box-shadow: inset 0 0 0 2px #111; }
|
|
25
|
+
.shared-browser-viewport[data-skin="phone"] .shared-browser-monitor::after { top: -27px; bottom: auto; right: calc(50% + 39px); width: 6px; height: 6px; background: #283d52; box-shadow: 0 0 0 2px #08090a; }
|
|
26
|
+
.shared-browser-viewport[data-skin="phone"] .shared-browser-monitor-detail { position: absolute; top: -26px; left: 50%; transform: translateX(-50%); width: 42px; height: 5px; border-radius: 4px; background: #08090a; box-shadow: 0 1px 0 #383b3d; }
|
|
27
|
+
.shared-browser-viewport[data-skin="phone"] .shared-browser-monitor-brand { left: auto; right: 10px; bottom: -34px; font-size: 10px; color: #92979c; }
|
|
28
|
+
.shared-browser-viewport[data-skin="phone"] .shared-browser-monitor-stand { display: none; }
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
@import url("./shared-browser-skins.css");
|
|
2
|
+
|
|
3
|
+
/* Shared browser uses the existing mutually exclusive right workbench. */
|
|
4
|
+
.shared-browser-panel { width: 50%; max-width: 780px; min-width: 360px; height: calc(100% - 16px); align-self: center; margin: 8px 8px 8px 10px; border: 1px solid var(--border); border-radius: 12px; background: var(--bg); display: flex; flex-direction: column; overflow: hidden; flex-shrink: 0; box-shadow: 4px 8px 18px rgba(var(--shadow-rgb), .14); }
|
|
5
|
+
.shared-browser-panel.hidden, #shared-browser-btn.hidden { display: none; }
|
|
6
|
+
.shared-browser-panel.shared-browser-wide { width: 70%; max-width: 1280px; }
|
|
7
|
+
.shared-browser-panel.panel-fullscreen { width: 100%; max-width: none; min-width: 0; height: 100%; margin: 0; border: 0; border-radius: 0; }
|
|
8
|
+
.shared-browser-header { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-bottom: 1px solid var(--border); }
|
|
9
|
+
.shared-browser-title { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; }
|
|
10
|
+
.shared-browser-panel svg { width: 15px; height: 15px; flex-shrink: 0; }
|
|
11
|
+
.shared-browser-phase { font-size: 10px; color: var(--text-muted); }
|
|
12
|
+
.shared-browser-phase[data-live="true"]::before { content: ''; display: inline-block; width: 5px; height: 5px; margin-right: 5px; border-radius: 50%; background: var(--accent); }
|
|
13
|
+
.shared-browser-window { display: flex; margin-left: auto; gap: 2px; }
|
|
14
|
+
.shared-browser-panel button { display: inline-flex; align-items: center; justify-content: center; background: transparent; color: var(--text); border: 0; border-radius: 6px; padding: 7px; cursor: pointer; font: inherit; }
|
|
15
|
+
.shared-browser-panel button:hover { background: var(--bg-alt); }
|
|
16
|
+
.shared-browser-panel button:disabled, .shared-browser-panel input:disabled, .shared-browser-panel select:disabled { opacity: .45; cursor: default; }
|
|
17
|
+
.shared-browser-panel button:focus-visible, #shared-browser-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
18
|
+
.shared-browser-address { display: flex; align-items: center; gap: 3px; padding: 8px; border-bottom: 1px solid var(--border); }
|
|
19
|
+
.shared-browser-address input { flex: 1; width: 0; min-width: 0; background: var(--bg-alt); color: var(--text); border: 1px solid var(--border); border-radius: 6px; padding: 7px 9px; font: inherit; font-size: 11px; }
|
|
20
|
+
.shared-browser-viewport { position: relative; flex: 1; min-height: 0; background: #202224; overflow: hidden; display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 44px; }
|
|
21
|
+
.shared-browser-monitor { position: relative; flex-shrink: 0; box-sizing: content-box; border: 10px solid #e7e2d6; border-bottom-width: 32px; border-radius: 13px; background: #111315; box-shadow: 0 2px 0 #b8b2a5, 0 18px 36px rgba(0,0,0,.28), 0 0 0 1px #f5f0e6; }
|
|
22
|
+
.shared-browser-monitor::before { content: ""; position: absolute; inset: -1px; border-radius: 3px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.25); pointer-events: none; }
|
|
23
|
+
.shared-browser-monitor::after { content: ""; position: absolute; bottom: -20px; right: 4px; width: 5px; height: 5px; border-radius: 50%; background: #aaa697; box-shadow: inset 0 1px 2px rgba(0,0,0,.25); }
|
|
24
|
+
.shared-browser-monitor[data-live="true"]::after { background: #79a582; box-shadow: 0 0 5px rgba(121,165,130,.4), inset 0 1px 1px rgba(0,0,0,.15); }
|
|
25
|
+
.shared-browser-monitor-brand { position: absolute; left: 5px; bottom: -25px; color: #787469; font-family: "Source Serif 4", Georgia, serif; font-size: 15px; font-weight: 600; font-synthesis: none; letter-spacing: -.012em; line-height: 24px; pointer-events: none; }
|
|
26
|
+
.shared-browser-monitor-stand { position: absolute; left: 50%; bottom: -57px; width: clamp(80px, 28%, 180px); height: 25px; transform: translateX(-50%); pointer-events: none; }
|
|
27
|
+
.shared-browser-monitor-stand::before { content: ""; position: absolute; top: 0; bottom: 3px; left: 30%; right: 30%; background: linear-gradient(#aaa69c, #d2cdbf); clip-path: polygon(18% 0, 82% 0, 100% 100%, 0 100%); }
|
|
28
|
+
.shared-browser-monitor-stand::after { content: ""; position: absolute; inset: auto 0 0; height: 4px; background: #d8d3c6; border-radius: 2px; box-shadow: 0 1px 0 #9b978d, 0 6px 10px rgba(0,0,0,.22); }
|
|
29
|
+
.shared-browser-monitor-label { color: #a5aaaf; font-size: 10px; font-variant-numeric: tabular-nums; letter-spacing: .04em; }
|
|
30
|
+
.shared-browser-monitor .shared-browser-empty { color: #a5aaaf; }
|
|
31
|
+
.shared-browser-monitor .shared-browser-empty h3 { color: #eceeef; }
|
|
32
|
+
.shared-browser-viewport canvas { display: block; width: 100%; height: 100%; object-fit: contain; touch-action: none; }
|
|
33
|
+
.shared-browser-keyboard { position: absolute; bottom: 0; left: 50%; width: 1px; height: 1px; opacity: 0; padding: 0; border: 0; }
|
|
34
|
+
.shared-browser-empty { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 30px; text-align: center; color: var(--text-muted); pointer-events: none; }
|
|
35
|
+
.shared-browser-empty.hidden { display: none; }
|
|
36
|
+
.shared-browser-empty > svg { width: 28px; height: 28px; opacity: .65; }
|
|
37
|
+
.shared-browser-empty h3 { font-size: 14px; font-weight: 500; color: var(--text); margin: 16px 0 0; }
|
|
38
|
+
.shared-browser-empty p { font-size: 12px; line-height: 1.6; }
|
|
39
|
+
.shared-browser-empty .shared-browser-private { font-size: 10px; margin-top: 20px; }
|
|
40
|
+
.shared-browser-footer { display: flex; align-items: center; gap: 10px; flex-shrink: 0; min-height: 40px; padding: 5px 10px; border-top: 1px solid var(--border); font-size: 10px; }
|
|
41
|
+
.shared-browser-control, .shared-browser-details { display: flex; align-items: center; gap: 6px; min-width: 0; }
|
|
42
|
+
.shared-browser-control span { color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
43
|
+
.shared-browser-footer button { padding: 5px 6px; white-space: nowrap; flex-shrink: 0; }
|
|
44
|
+
.shared-browser-footer button[hidden] { display: none; }
|
|
45
|
+
.shared-browser-control button { border: 1px solid var(--border); }
|
|
46
|
+
.shared-browser-details { margin-left: auto; flex-shrink: 0; color: var(--text-muted); }
|
|
47
|
+
.shared-browser-details select { font: inherit; background: transparent; color: var(--text-muted); border: 0; padding: 4px 0; cursor: pointer; }
|
|
48
|
+
.shared-browser-details [data-action="end"] { color: var(--text-muted); border-left: 1px solid var(--border); border-radius: 0; padding-left: 10px; }
|
|
49
|
+
.shared-browser-error.hidden { display: none; }
|
|
50
|
+
.shared-browser-error { padding: 8px 12px; margin: 0; font-size: 11px; color: var(--text); background: var(--bg-alt); }
|
|
51
|
+
@media (max-width: 1023px) { #shared-browser-panel, #shared-browser-btn { display: none !important; } }
|
|
52
|
+
|
|
53
|
+
.shared-browser-resolution { position: relative; }
|
|
54
|
+
.shared-browser-resolution [data-viewport-trigger] { gap: 5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
|
|
55
|
+
.shared-browser-resolution [data-viewport-trigger] svg { width: 11px; height: 11px; }
|
|
56
|
+
.shared-browser-resolution-menu { position: absolute; z-index: 10; right: 0; bottom: calc(100% + 9px); width: 158px; max-height: min(260px, 50vh); overflow-y: auto; padding: 5px; border: 1px solid var(--border); border-radius: 9px; background: var(--bg); box-shadow: 0 8px 28px rgba(0,0,0,.25); }
|
|
57
|
+
.shared-browser-resolution-menu[hidden] { display: none; }
|
|
58
|
+
.shared-browser-resolution-menu button { display: flex; justify-content: space-between; width: 100%; padding: 8px 10px; text-align: left; font-size: 11px; font-variant-numeric: tabular-nums; }
|
|
59
|
+
.shared-browser-resolution-menu button[aria-checked="true"] { background: var(--bg-alt); color: var(--text); }
|
|
60
|
+
.shared-browser-resolution-menu button[aria-checked="true"]::after { content: "✓"; color: var(--accent); }
|
|
61
|
+
|
|
62
|
+
.shared-browser-caption { display: flex; flex-direction: column; align-items: center; gap: 10px; width: calc(100% - 40px); max-width: 590px; text-align: center; }
|
|
63
|
+
.shared-browser-activity { position: relative; width: 100%; max-width: 590px; }
|
|
64
|
+
.shared-browser-activity[hidden], .shared-browser-pointer[hidden] { display: none; }
|
|
65
|
+
.shared-browser-caption-history { max-height: 170px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; scrollbar-color: #70757a transparent; padding: 8px 16px; text-align: center; }
|
|
66
|
+
.shared-browser-caption-history:focus-visible { outline: 1px solid #92979c; outline-offset: 2px; border-radius: 6px; }
|
|
67
|
+
.shared-browser-caption-row { margin: 0 0 14px; color: #fff; font-size: clamp(16px, 1.5vw, 21px); line-height: 1.5; font-weight: 600; text-shadow: 0 2px 3px #000, 1px 0 2px #000, -1px 0 2px #000; overflow-wrap: anywhere; }
|
|
68
|
+
.shared-browser-caption-row:last-child { margin-bottom: 0; }
|
|
69
|
+
.shared-browser-activity-text { padding: 2px 7px; background: rgba(0,0,0,.62); box-decoration-break: clone; -webkit-box-decoration-break: clone; border-radius: 3px; }
|
|
70
|
+
.shared-browser-caption-row[data-age="1"] { opacity: .7; }
|
|
71
|
+
.shared-browser-caption-row[data-age="2"] { opacity: .48; }
|
|
72
|
+
.shared-browser-caption-row[data-age="3"] { opacity: .3; }
|
|
73
|
+
.shared-browser-activity[data-reviewing="true"] .shared-browser-caption-row { opacity: .9; }
|
|
74
|
+
.shared-browser-caption-row small { display: block; margin-top: 5px; font-size: 11px; font-weight: 400; color: #edc6ae; }
|
|
75
|
+
.shared-browser-panel .shared-browser-caption-latest { position: absolute; bottom: -25px; left: 50%; transform: translateX(-50%); padding: 3px 9px; font-size: 10px; white-space: nowrap; color: #eceeef; background: #353a3f; border: 1px solid #62686e; border-radius: 12px; }
|
|
76
|
+
.shared-browser-caption-latest[hidden] { display: none; }
|
|
77
|
+
.shared-browser-caption-announcement { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
|
|
78
|
+
.shared-browser-pointer-layer { position: absolute; inset: 0; z-index: 2; pointer-events: none; overflow: hidden; }
|
|
79
|
+
.shared-browser-pointer { position: absolute; width: 24px; height: 28px; transition: left .12s linear, top .12s linear; filter: drop-shadow(0 2px 2px #0006); }
|
|
80
|
+
.shared-browser-pointer svg { width: 24px; height: 28px; fill: #8076f5; stroke: white; stroke-width: 1.6; }
|
|
81
|
+
.shared-browser-pointer i { position: absolute; left: -12px; top: -12px; width: 30px; height: 30px; border: 2px solid #a59dff; border-radius: 50%; opacity: 0; }
|
|
82
|
+
@media (prefers-reduced-motion: reduce) { .shared-browser-pointer { transition: none; } }
|
|
83
|
+
|
|
84
|
+
.shared-browser-tabs { display: flex; gap: 4px; align-items: center; overflow-x: auto; flex-shrink: 0; padding: 6px 8px 0; border-bottom: 1px solid var(--border); }
|
|
85
|
+
.shared-browser-tab { display: flex; align-items: center; min-width: 100px; max-width: 210px; border-radius: 7px 7px 0 0; background: var(--bg-alt); }
|
|
86
|
+
.shared-browser-tab:has([aria-selected="true"]) { box-shadow: inset 0 -2px var(--accent); background: var(--bg-surface, var(--bg-alt)); }
|
|
87
|
+
.shared-browser-tab [role="tab"] { min-width: 0; gap: 8px; font-size: 11px; padding: 9px 8px; }
|
|
88
|
+
.shared-browser-tab [role="tab"] span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
89
|
+
.shared-browser-tab small { font-size: 9px; color: var(--text-muted); }
|
|
90
|
+
.shared-browser-tab [aria-selected="true"] small { color: var(--accent); }
|
|
91
|
+
.shared-browser-tab > button:last-child { padding: 5px; font-size: 15px; color: var(--text-muted); }
|
|
@@ -561,12 +561,6 @@
|
|
|
561
561
|
flex-direction: column;
|
|
562
562
|
overflow: hidden;
|
|
563
563
|
flex-shrink: 0;
|
|
564
|
-
box-shadow:
|
|
565
|
-
4px 8px 18px rgba(var(--shadow-rgb), 0.14),
|
|
566
|
-
2px 2px 4px rgba(var(--shadow-rgb), 0.08),
|
|
567
|
-
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
|
568
|
-
animation: workbench-panel-in 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
569
|
-
transition: max-width 0.2s ease, width 0.2s ease, box-shadow 0.2s ease;
|
|
570
564
|
}
|
|
571
565
|
#notes-browser.hidden { display: none; }
|
|
572
566
|
#notes-browser.notes-browser-wide { width: 70%; max-width: 1200px; }
|
|
@@ -578,14 +572,9 @@
|
|
|
578
572
|
margin: 0;
|
|
579
573
|
border: 0;
|
|
580
574
|
border-radius: 0;
|
|
581
|
-
box-shadow: none;
|
|
582
|
-
animation: none;
|
|
583
575
|
}
|
|
584
576
|
}
|
|
585
577
|
|
|
586
|
-
@media (prefers-reduced-motion: reduce) {
|
|
587
|
-
#notes-browser { animation: none; }
|
|
588
|
-
}
|
|
589
578
|
|
|
590
579
|
/* Narrow screens: full viewport overlay, like the other workbench tools. */
|
|
591
580
|
@media (max-width: 1023px) {
|
package/lib/public/index.html
CHANGED
|
@@ -57,28 +57,6 @@
|
|
|
57
57
|
<div id="top-bar">
|
|
58
58
|
<div class="top-bar-left-pills">
|
|
59
59
|
<button id="pwa-install-pill" class="top-bar-install-btn hidden" title="Open as app"><i data-lucide="download"></i> Open as app</button>
|
|
60
|
-
<div id="ext-pill-wrap" class="ext-pill-wrap">
|
|
61
|
-
<button id="ext-pill" class="top-bar-ext-btn hidden" title="Chrome Extension"><i data-lucide="puzzle"></i> Extension</button>
|
|
62
|
-
<div id="ext-popover" class="ext-popover">
|
|
63
|
-
<div class="ext-popover-header">
|
|
64
|
-
<div class="ext-popover-title">Clay for Chrome <span class="ext-experimental">Experimental</span></div>
|
|
65
|
-
<div class="ext-popover-sub">v0.1.0 · <a href="https://github.com/chadbyte/clay-chrome" target="_blank" rel="noopener">GitHub</a></div>
|
|
66
|
-
</div>
|
|
67
|
-
<div class="ext-popover-connected hidden" id="ext-connected-banner"><i data-lucide="check-circle"></i> Extension connected</div>
|
|
68
|
-
<div class="ext-popover-desc" id="ext-popover-desc">Connect your browser to Clay. Gives Claude visibility into open tabs, console, network, DOM, and screenshots.</div>
|
|
69
|
-
<button class="ext-popover-download" id="ext-download-btn"><i data-lucide="download"></i> Download Extension (.zip)</button>
|
|
70
|
-
<div class="ext-popover-status hidden" id="ext-download-status"></div>
|
|
71
|
-
<div class="ext-popover-divider" id="ext-popover-divider"></div>
|
|
72
|
-
<div class="ext-popover-guide-title" id="ext-popover-guide-title">Installation</div>
|
|
73
|
-
<div class="ext-popover-steps">
|
|
74
|
-
<div class="ext-popover-step"><span class="ext-snum">1</span> Download above, then unzip to a permanent folder.</div>
|
|
75
|
-
<div class="ext-popover-step"><span class="ext-snum">2</span> Open <code id="ext-copy-url" class="ext-popover-code" title="Click to copy">chrome://extensions</code></div>
|
|
76
|
-
<div class="ext-popover-step"><span class="ext-snum">3</span> Enable <strong>Developer mode</strong> (top-right toggle).</div>
|
|
77
|
-
<div class="ext-popover-step"><span class="ext-snum">4</span> <strong>Load unpacked</strong> > select the unzipped folder.</div>
|
|
78
|
-
<div class="ext-popover-step"><span class="ext-snum">5</span> Refresh this page. Done!</div>
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
60
|
<div id="update-pill-wrap" class="top-bar-update hidden">
|
|
83
61
|
<button id="update-pill" class="top-bar-update-btn"><i data-lucide="arrow-up-circle"></i> <span id="update-version"></span> is available. Update now</button>
|
|
84
62
|
<div id="update-popover" class="top-bar-popover">
|
|
@@ -1768,6 +1746,36 @@
|
|
|
1768
1746
|
<span class="mcp-title"><i data-lucide="cable"></i> MCP Servers</span>
|
|
1769
1747
|
<button class="skills-close" id="mcp-modal-close"><i data-lucide="x"></i></button>
|
|
1770
1748
|
</div>
|
|
1749
|
+
<div id="ext-pill-wrap" class="ext-pill-wrap">
|
|
1750
|
+
<button id="ext-pill" class="top-bar-ext-btn" title="Chrome Extension" aria-expanded="false" aria-controls="ext-popover"><i data-lucide="puzzle"></i> Extension</button>
|
|
1751
|
+
<p class="ext-feature-summary">Connect your Chrome tabs and local MCP tools to Clay.</p>
|
|
1752
|
+
<div id="ext-popover" class="ext-popover">
|
|
1753
|
+
<div class="ext-popover-header">
|
|
1754
|
+
<div class="ext-popover-title">Clay for Chrome <span class="ext-experimental">Experimental</span></div>
|
|
1755
|
+
<div class="ext-popover-sub">v0.1.0 · <a href="https://github.com/chadbyte/clay-chrome" target="_blank" rel="noopener">GitHub</a></div>
|
|
1756
|
+
</div>
|
|
1757
|
+
<div class="ext-popover-connected hidden" id="ext-connected-banner"><i data-lucide="check-circle"></i> Extension connected</div>
|
|
1758
|
+
<div class="ext-popover-desc" id="ext-popover-desc">
|
|
1759
|
+
<p>With Clay for Chrome, your agent can:</p>
|
|
1760
|
+
<ul class="ext-feature-list">
|
|
1761
|
+
<li><strong>Work with your open tabs.</strong> Read pages, capture screenshots, click buttons and fill in forms.</li>
|
|
1762
|
+
<li><strong>Help debug a website.</strong> Inspect page structure, console errors and network requests.</li>
|
|
1763
|
+
<li><strong>Use MCP tools on your computer.</strong> Add MCP servers in the extension and connect them through the separately installed Clay MCP Bridge.</li>
|
|
1764
|
+
</ul>
|
|
1765
|
+
</div>
|
|
1766
|
+
<button class="ext-popover-download" id="ext-download-btn"><i data-lucide="download"></i> Download Extension (.zip)</button>
|
|
1767
|
+
<div class="ext-popover-status hidden" id="ext-download-status"></div>
|
|
1768
|
+
<div class="ext-popover-divider" id="ext-popover-divider"></div>
|
|
1769
|
+
<div class="ext-popover-guide-title" id="ext-popover-guide-title">Installation</div>
|
|
1770
|
+
<div class="ext-popover-steps">
|
|
1771
|
+
<div class="ext-popover-step"><span class="ext-snum">1</span> Download above, then unzip to a permanent folder.</div>
|
|
1772
|
+
<div class="ext-popover-step"><span class="ext-snum">2</span> Open <code id="ext-copy-url" class="ext-popover-code" title="Click to copy">chrome://extensions</code></div>
|
|
1773
|
+
<div class="ext-popover-step"><span class="ext-snum">3</span> Enable <strong>Developer mode</strong> (top-right toggle).</div>
|
|
1774
|
+
<div class="ext-popover-step"><span class="ext-snum">4</span> <strong>Load unpacked</strong> > select the unzipped folder.</div>
|
|
1775
|
+
<div class="ext-popover-step"><span class="ext-snum">5</span> Refresh this page. Done!</div>
|
|
1776
|
+
</div>
|
|
1777
|
+
</div>
|
|
1778
|
+
</div>
|
|
1771
1779
|
<div class="mcp-content" id="mcp-content">
|
|
1772
1780
|
<p class="mcp-no-servers">No MCP servers detected. Configure in Clay Chrome Extension.</p>
|
|
1773
1781
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { handleSharedBrowserMessage } from './shared-browser.js';
|
|
1
2
|
import { syncGithubSessions } from './session-github.js';
|
|
2
3
|
import { handleIssuesMessageInContext as handleIssuesMessage } from './issues-context.js';
|
|
3
4
|
// app-messages.js - WebSocket message router
|
|
@@ -104,6 +105,7 @@ var connectOverlay = document.getElementById("connect-overlay");
|
|
|
104
105
|
initMessageDeliveryUi();
|
|
105
106
|
|
|
106
107
|
export function processMessage(msg) {
|
|
108
|
+
if (handleSharedBrowserMessage(msg)) return;
|
|
107
109
|
if (msg.type === "vendor_login_browser_frame" || msg.type === "vendor_login_browser_status") {
|
|
108
110
|
handleLoginBrowserMessage(msg);
|
|
109
111
|
return;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { openMcpSkillsWorkbench } from "./mcp-skills-workbench.js";
|
|
2
|
+
import { copyToClipboard, showToast } from "./utils.js";
|
|
3
|
+
import { iconHtml, refreshIcons } from "./icons.js";
|
|
4
|
+
|
|
5
|
+
export function initExtensionSettings() {
|
|
6
|
+
var extPillWrap = document.getElementById("ext-pill-wrap");
|
|
7
|
+
var extPillBtn = document.getElementById("ext-pill");
|
|
8
|
+
var extPopover = document.getElementById("ext-popover");
|
|
9
|
+
var extDownloadBtn = document.getElementById("ext-download-btn");
|
|
10
|
+
var extDownloadStatus = document.getElementById("ext-download-status");
|
|
11
|
+
var extCopyUrl = document.getElementById("ext-copy-url");
|
|
12
|
+
if (!extPillWrap || !extPillBtn || !extPopover) return;
|
|
13
|
+
|
|
14
|
+
// Detect extension connection via postMessage from content.js
|
|
15
|
+
|
|
16
|
+
var connectedBanner = document.getElementById("ext-connected-banner");
|
|
17
|
+
var extDivider = document.getElementById("ext-popover-divider");
|
|
18
|
+
var extGuideTitle = document.getElementById("ext-popover-guide-title");
|
|
19
|
+
var extSteps = extPopover.querySelector(".ext-popover-steps");
|
|
20
|
+
|
|
21
|
+
function setExtConnected() {
|
|
22
|
+
if (extPillBtn.classList.contains("ext-connected")) return;
|
|
23
|
+
extPillBtn.classList.add("ext-connected");
|
|
24
|
+
extPillBtn.innerHTML = '<i data-lucide="check"></i> Extension';
|
|
25
|
+
refreshIcons(extPillBtn);
|
|
26
|
+
if (connectedBanner) connectedBanner.classList.remove("hidden");
|
|
27
|
+
if (extDownloadBtn) extDownloadBtn.style.display = "none";
|
|
28
|
+
if (extDownloadStatus) extDownloadStatus.classList.add("hidden");
|
|
29
|
+
if (extDivider) extDivider.style.display = "none";
|
|
30
|
+
if (extGuideTitle) extGuideTitle.style.display = "none";
|
|
31
|
+
if (extSteps) extSteps.style.display = "none";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
window.addEventListener("message", function (event) {
|
|
35
|
+
if (event.source !== window) return;
|
|
36
|
+
if (!event.data || event.data.source !== "clay-chrome-extension") return;
|
|
37
|
+
setExtConnected();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Toggle popover
|
|
41
|
+
extPillBtn.addEventListener("click", function (e) {
|
|
42
|
+
e.stopPropagation();
|
|
43
|
+
openMcpSkillsWorkbench("mcp");
|
|
44
|
+
var expanded = extPopover.classList.toggle("visible");
|
|
45
|
+
extPillBtn.setAttribute("aria-expanded", String(expanded));
|
|
46
|
+
refreshIcons(extPopover);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
document.addEventListener("click", function (e) {
|
|
50
|
+
if (!extPopover.contains(e.target) && e.target !== extPillBtn && !extPillBtn.contains(e.target)) {
|
|
51
|
+
extPopover.classList.remove("visible");
|
|
52
|
+
extPillBtn.setAttribute("aria-expanded", "false");
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Download button
|
|
57
|
+
if (extDownloadBtn) {
|
|
58
|
+
extDownloadBtn.addEventListener("click", function (e) {
|
|
59
|
+
e.stopPropagation();
|
|
60
|
+
extDownloadBtn.disabled = true;
|
|
61
|
+
extDownloadBtn.innerHTML = iconHtml("loader") + " Downloading...";
|
|
62
|
+
refreshIcons(extDownloadBtn);
|
|
63
|
+
var loaderIcon = extDownloadBtn.querySelector(".lucide");
|
|
64
|
+
if (loaderIcon) loaderIcon.style.animation = "spin 1s linear infinite";
|
|
65
|
+
if (extDownloadStatus) {
|
|
66
|
+
extDownloadStatus.classList.remove("hidden");
|
|
67
|
+
extDownloadStatus.textContent = "Fetching from GitHub...";
|
|
68
|
+
extDownloadStatus.style.color = "";
|
|
69
|
+
}
|
|
70
|
+
fetch("/api/extension/download").then(function (resp) {
|
|
71
|
+
if (!resp.ok) throw new Error("Download failed (" + resp.status + ")");
|
|
72
|
+
return resp.blob();
|
|
73
|
+
}).then(function (blob) {
|
|
74
|
+
var url = URL.createObjectURL(blob);
|
|
75
|
+
var a = document.createElement("a");
|
|
76
|
+
a.href = url;
|
|
77
|
+
a.download = "clay-chrome-extension.zip";
|
|
78
|
+
document.body.appendChild(a);
|
|
79
|
+
a.click();
|
|
80
|
+
document.body.removeChild(a);
|
|
81
|
+
URL.revokeObjectURL(url);
|
|
82
|
+
if (extDownloadStatus) {
|
|
83
|
+
extDownloadStatus.textContent = "Download complete!";
|
|
84
|
+
extDownloadStatus.style.color = "var(--accent)";
|
|
85
|
+
}
|
|
86
|
+
showToast("Extension downloaded");
|
|
87
|
+
}).catch(function (err) {
|
|
88
|
+
if (extDownloadStatus) {
|
|
89
|
+
extDownloadStatus.textContent = "Failed: " + err.message;
|
|
90
|
+
extDownloadStatus.style.color = "var(--danger, #e53935)";
|
|
91
|
+
}
|
|
92
|
+
showToast("Download failed");
|
|
93
|
+
}).finally(function () {
|
|
94
|
+
extDownloadBtn.disabled = false;
|
|
95
|
+
extDownloadBtn.innerHTML = iconHtml("download") + " Download Extension (.zip)";
|
|
96
|
+
refreshIcons(extDownloadBtn);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Copy chrome://extensions URL
|
|
102
|
+
if (extCopyUrl) {
|
|
103
|
+
extCopyUrl.addEventListener("click", function (e) {
|
|
104
|
+
e.stopPropagation();
|
|
105
|
+
copyToClipboard("chrome://extensions").then(function () {
|
|
106
|
+
showToast("Copied chrome://extensions");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
3
|
+
import { claimRightWorkbench, registerRightWorkbench, releaseRightWorkbench } from './right-workbench.js';
|
|
4
|
+
|
|
5
|
+
function state() { return store.get('mcpSkillsWorkbench') || {}; }
|
|
6
|
+
function patch(value) { store.set({ mcpSkillsWorkbench: Object.assign({}, state(), value) }); }
|
|
7
|
+
function skillsAllowed() { var permissions = store.get('permissions'); return !permissions || permissions.skills !== false; }
|
|
8
|
+
export function ensureMcpSkillsWorkbench() {
|
|
9
|
+
var panel = document.getElementById('mcp-skills-workbench');
|
|
10
|
+
if (panel) return panel;
|
|
11
|
+
var root = document.getElementById('main-panels');
|
|
12
|
+
if (!root) return null;
|
|
13
|
+
panel = document.createElement('section'); panel.id = 'mcp-skills-workbench'; panel.className = 'mcp-skills-workbench hidden'; panel.setAttribute('aria-label', 'MCP / Skills');
|
|
14
|
+
panel.innerHTML = '<header class="mcp-skills-header"><strong>' + iconHtml('blocks') + 'MCP / Skills</strong><div>' +
|
|
15
|
+
'<button type="button" data-workbench="wide" aria-label="Widen MCP / Skills">' + iconHtml('chevrons-left-right') + '</button>' +
|
|
16
|
+
'<button type="button" data-workbench="fullscreen" aria-label="Toggle MCP / Skills fullscreen">' + iconHtml('maximize-2') + '</button>' +
|
|
17
|
+
'<button type="button" data-workbench="close" aria-label="Close MCP / Skills">' + iconHtml('x') + '</button></div></header>' +
|
|
18
|
+
'<div class="mcp-skills-tabs" role="tablist" aria-label="MCP / Skills sections"><button id="mcp-workbench-tab" role="tab" data-section="mcp" aria-controls="mcp-modal">MCP Servers</button><button id="skills-workbench-tab" role="tab" data-section="skills" aria-controls="skills-modal">Skills</button></div>';
|
|
19
|
+
['mcp', 'skills'].forEach(function (name) {
|
|
20
|
+
var section = document.getElementById(name + '-modal');
|
|
21
|
+
if (!section) return;
|
|
22
|
+
var backdrop = section.querySelector('.confirm-backdrop'); if (backdrop) backdrop.remove();
|
|
23
|
+
var dialog = section.querySelector('.confirm-dialog'); if (dialog) dialog.classList.remove('confirm-dialog');
|
|
24
|
+
section.setAttribute('role', 'tabpanel'); section.setAttribute('aria-labelledby', name + '-workbench-tab');
|
|
25
|
+
panel.appendChild(section);
|
|
26
|
+
});
|
|
27
|
+
root.appendChild(panel);
|
|
28
|
+
panel.querySelector('[data-workbench="close"]').onclick = closeMcpSkillsWorkbench;
|
|
29
|
+
['wide', 'fullscreen'].forEach(function (key) { panel.querySelector('[data-workbench="' + key + '"]').onclick = function () { var value = {}; value[key] = !state()[key]; patch(value); }; });
|
|
30
|
+
panel.querySelectorAll('[data-section]').forEach(function (button) {
|
|
31
|
+
button.onclick = function () { openMcpSkillsWorkbench(button.dataset.section); };
|
|
32
|
+
button.onkeydown = function (event) {
|
|
33
|
+
if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return;
|
|
34
|
+
event.preventDefault(); var tab = button.dataset.section === 'mcp' && skillsAllowed() ? 'skills' : 'mcp';
|
|
35
|
+
if (event.key === 'Home') tab = 'mcp'; if (event.key === 'End' && skillsAllowed()) tab = 'skills';
|
|
36
|
+
openMcpSkillsWorkbench(tab); panel.querySelector('[data-section="' + tab + '"]').focus();
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
// Compatibility targets for older mobile entry points; never palette tiles.
|
|
40
|
+
['skills-btn', 'mate-skills-btn'].forEach(function (id) {
|
|
41
|
+
if (document.getElementById(id)) return;
|
|
42
|
+
var button = document.createElement('button'); button.id = id; button.hidden = true;
|
|
43
|
+
button.onclick = function () { openMcpSkillsWorkbench('skills'); }; root.appendChild(button);
|
|
44
|
+
});
|
|
45
|
+
refreshIcons(panel); render(); return panel;
|
|
46
|
+
}
|
|
47
|
+
export function openMcpSkillsWorkbench(tab) {
|
|
48
|
+
if (!ensureMcpSkillsWorkbench()) return;
|
|
49
|
+
tab = tab || state().tab || 'mcp';
|
|
50
|
+
if (tab === 'skills' && !skillsAllowed()) tab = 'mcp';
|
|
51
|
+
claimRightWorkbench('mcp-skills'); patch({ open: true, tab: tab });
|
|
52
|
+
}
|
|
53
|
+
export function closeMcpSkillsWorkbench() { patch({ open: false }); releaseRightWorkbench('mcp-skills'); }
|
|
54
|
+
function render() {
|
|
55
|
+
var panel = document.getElementById('mcp-skills-workbench'); if (!panel) return;
|
|
56
|
+
var current = state(); var tab = current.tab || 'mcp';
|
|
57
|
+
panel.classList.toggle('hidden', !current.open); panel.classList.toggle('workbench-wide', !!current.wide); panel.classList.toggle('panel-fullscreen', !!current.fullscreen);
|
|
58
|
+
['wide', 'fullscreen'].forEach(function (key) { panel.querySelector('[data-workbench="' + key + '"]').setAttribute('aria-pressed', String(!!current[key])); });
|
|
59
|
+
panel.querySelectorAll('[data-section]').forEach(function (button) { var selected = button.dataset.section === tab; button.setAttribute('aria-selected', String(selected)); button.tabIndex = selected ? 0 : -1; button.hidden = button.dataset.section === 'skills' && !skillsAllowed(); });
|
|
60
|
+
['mcp', 'skills'].forEach(function (name) { var section = document.getElementById(name + '-modal'); if (section) section.classList.toggle('hidden', !current.open || name !== tab); });
|
|
61
|
+
}
|
|
62
|
+
registerRightWorkbench('mcp-skills', closeMcpSkillsWorkbench);
|
|
63
|
+
store.subscribe(function (current, previous) {
|
|
64
|
+
if (current.currentSlug !== previous.currentSlug || current.myUserId !== previous.myUserId || current.dmMode !== previous.dmMode) { closeMcpSkillsWorkbench(); return; }
|
|
65
|
+
if (current.permissions !== previous.permissions && !skillsAllowed() && state().tab === 'skills') { patch({ tab: 'mcp' }); return; }
|
|
66
|
+
if (current.mcpSkillsWorkbench !== previous.mcpSkillsWorkbench || current.permissions !== previous.permissions) render();
|
|
67
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ensureMcpSkillsWorkbench, openMcpSkillsWorkbench, closeMcpSkillsWorkbench } from './mcp-skills-workbench.js';
|
|
1
2
|
// mcp-ui.js - MCP Servers modal (sidebar button + panel)
|
|
2
3
|
// Renders available MCP servers with per-project toggle checkboxes.
|
|
3
4
|
|
|
@@ -69,6 +70,7 @@ export function mcpPermissionModeApplicability(state) {
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
export function initMcp() {
|
|
73
|
+
ensureMcpSkillsWorkbench();
|
|
72
74
|
modal = document.getElementById("mcp-modal");
|
|
73
75
|
contentEl = document.getElementById("mcp-content");
|
|
74
76
|
|
|
@@ -87,6 +89,7 @@ export function initMcp() {
|
|
|
87
89
|
state.currentMode !== prev.currentMode || state.effectivePermissionMode !== prev.effectivePermissionMode ||
|
|
88
90
|
state.permissionCapabilities !== prev.permissionCapabilities || state.mcpPermissionModeOverrides !== prev.mcpPermissionModeOverrides ||
|
|
89
91
|
state.mcpPermissionModePendingByTarget !== prev.mcpPermissionModePendingByTarget || state.connected !== prev.connected;
|
|
92
|
+
changed = changed || state.mcpSkillsWorkbench !== prev.mcpSkillsWorkbench;
|
|
90
93
|
if (changed && modal && !modal.classList.contains("hidden")) renderMcpServerList();
|
|
91
94
|
});
|
|
92
95
|
|
|
@@ -126,14 +129,14 @@ export function getMcpServers() {
|
|
|
126
129
|
|
|
127
130
|
function openMcpModal() {
|
|
128
131
|
if (!modal) return;
|
|
129
|
-
|
|
132
|
+
openMcpSkillsWorkbench("mcp");
|
|
130
133
|
refreshIcons(modal);
|
|
131
134
|
renderMcpServerList();
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
function closeMcpModal() {
|
|
135
138
|
if (!modal) return;
|
|
136
|
-
|
|
139
|
+
closeMcpSkillsWorkbench();
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
function updateBadge() {
|
|
@@ -272,11 +275,8 @@ function renderMcpServerList() {
|
|
|
272
275
|
label: "Setup Extension",
|
|
273
276
|
icon: "puzzle",
|
|
274
277
|
onClick: function () {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
var extPill = document.getElementById("ext-pill");
|
|
278
|
-
if (extPill) extPill.click();
|
|
279
|
-
}, 100);
|
|
278
|
+
var extPill = document.getElementById("ext-pill");
|
|
279
|
+
if (extPill && extPill.getAttribute("aria-expanded") !== "true") extPill.click();
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
}));
|
|
@@ -317,11 +317,8 @@ function renderMcpServerList() {
|
|
|
317
317
|
label: "Open Extension popup to add servers",
|
|
318
318
|
icon: "puzzle",
|
|
319
319
|
onClick: function () {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
var extPill = document.getElementById("ext-pill");
|
|
323
|
-
if (extPill) extPill.click();
|
|
324
|
-
}, 100);
|
|
320
|
+
var extPill = document.getElementById("ext-pill");
|
|
321
|
+
if (extPill && extPill.getAttribute("aria-expanded") !== "true") extPill.click();
|
|
325
322
|
}
|
|
326
323
|
} : null
|
|
327
324
|
}));
|