clay-server 4.7.1-beta.5 → 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/bin/login-browser-open.js +7 -0
- 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-vendor-login.js +52 -18
- package/lib/project.js +38 -1
- package/lib/public/app.js +8 -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/css/vendor-login-browser.css +63 -0
- package/lib/public/index.html +30 -22
- package/lib/public/modules/app-messages.js +7 -0
- package/lib/public/modules/app-notifications.js +1 -1
- 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/modules/vendor-login-browser.js +243 -0
- package/lib/public/modules/vendor-login.js +23 -4
- package/lib/public/style.css +7 -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/terminal.js +4 -0
- package/lib/vendor-login-browser-flow.js +46 -0
- package/lib/vendor-login-browser-passkeys.js +27 -0
- package/lib/vendor-login-browser-worker.js +149 -0
- package/lib/vendor-login-browser.js +162 -0
- package/lib/ws-schema.js +14 -0
- package/lib/yoke/skill-discovery.js +22 -2
- package/package.json +2 -1
|
@@ -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) {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
.login-browser {
|
|
2
|
+
width: min(820px, calc(100vw - 48px));
|
|
3
|
+
height: min(780px, calc(100dvh - 48px));
|
|
4
|
+
max-width: none;
|
|
5
|
+
max-height: none;
|
|
6
|
+
padding: 0;
|
|
7
|
+
margin: auto;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
border: 1px solid var(--border);
|
|
10
|
+
border-radius: 16px;
|
|
11
|
+
background: var(--bg);
|
|
12
|
+
color: var(--text);
|
|
13
|
+
box-shadow: 0 32px 100px #0005, 0 4px 16px #0003;
|
|
14
|
+
}
|
|
15
|
+
.login-browser[open] { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; }
|
|
16
|
+
.login-browser::backdrop { background: #0007; backdrop-filter: blur(6px); }
|
|
17
|
+
.login-browser-header { display: flex; align-items: center; gap: 12px; padding: 17px 20px; border-bottom: 1px solid var(--border); }
|
|
18
|
+
.login-browser-vendor { width: 34px; height: 34px; border-radius: 9px; object-fit: cover; }
|
|
19
|
+
.login-browser-heading { flex: 1; min-width: 0; }
|
|
20
|
+
.login-browser h2 { font-size: 15px; line-height: 1.4; font-weight: 600; letter-spacing: -.015em; margin: 0; }
|
|
21
|
+
.login-browser-origin { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; font-size: 11px; line-height: 1.5; color: var(--text-dimmer); }
|
|
22
|
+
.login-browser-actions { display: flex; align-items: center; gap: 3px; }
|
|
23
|
+
.login-browser button, .login-browser-more summary { font: inherit; cursor: pointer; color: var(--text-muted, var(--text)); }
|
|
24
|
+
.login-browser button { border: 0; background: transparent; }
|
|
25
|
+
.login-browser svg { width: 16px; height: 16px; flex-shrink: 0; stroke-width: 1.6; }
|
|
26
|
+
.login-browser .login-browser-icon, .login-browser-more summary { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; border-radius: 7px; }
|
|
27
|
+
.login-browser button:hover, .login-browser-more summary:hover { background: var(--bg-alt); color: var(--text); }
|
|
28
|
+
.login-browser button:focus-visible, .login-browser-more summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
29
|
+
.login-browser .login-browser-keyboard-button { display: none; }
|
|
30
|
+
.login-browser-more { position: relative; }
|
|
31
|
+
.login-browser-more summary { list-style: none; }
|
|
32
|
+
.login-browser-more summary::-webkit-details-marker { display: none; }
|
|
33
|
+
.login-browser-menu { position: absolute; right: 0; top: 39px; z-index: 3; width: 180px; padding: 5px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg); box-shadow: 0 8px 28px #0003; }
|
|
34
|
+
.login-browser-menu button { display: flex; align-items: center; gap: 9px; width: 100%; padding: 10px; border-radius: 6px; font-size: 12px; text-align: left; }
|
|
35
|
+
.login-browser-viewport { position: relative; min-height: 0; overflow: hidden; background: #fff; line-height: 0; }
|
|
36
|
+
.login-browser canvas { display: block; width: 100%; height: 100%; object-fit: contain; touch-action: none; }
|
|
37
|
+
.login-browser-loading { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; background: var(--bg-alt); color: var(--text-dimmer); font-size: 12px; line-height: 1.5; }
|
|
38
|
+
.login-browser-loading strong { font-size: 14px; font-weight: 500; color: var(--text); }
|
|
39
|
+
.login-browser-loading[hidden] { display: none; }
|
|
40
|
+
.login-browser-spinner { width: 22px; height: 22px; margin-bottom: 8px; border: 2px solid var(--border); border-top-color: var(--text-dimmer); border-radius: 50%; animation: login-browser-spin .9s linear infinite; }
|
|
41
|
+
.login-browser-keyboard { position: absolute; width: 1px; height: 1px; padding: 0; border: 0; bottom: 0; left: 50%; opacity: 0; font-size: 16px; }
|
|
42
|
+
.login-browser-footer { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 12px 18px; border-top: 1px solid var(--border); }
|
|
43
|
+
.login-browser-info { min-width: 0; }
|
|
44
|
+
.login-browser-status { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
45
|
+
.login-browser-status-dot { width: 5px; height: 5px; flex-shrink: 0; border-radius: 50%; background: var(--text-dimmer); }
|
|
46
|
+
.login-browser[data-phase="error"] .login-browser-status-dot { background: var(--warning, #d69c51); }
|
|
47
|
+
.login-browser-footer p { margin: 0; font-size: 11px; color: var(--text-dimmer); line-height: 1.5; }
|
|
48
|
+
.login-browser-footer .login-browser-privacy { margin-top: 5px; color: var(--text-muted, var(--text)); }
|
|
49
|
+
.login-browser .login-browser-terminal { display: inline-flex; align-items: center; justify-content: center; gap: 7px; flex-shrink: 0; padding: 8px 10px; border: 1px solid var(--border); border-radius: 7px; font-size: 11px; font-weight: 500; color: var(--text); }
|
|
50
|
+
.login-browser-terminal svg:last-child { width: 12px; height: 12px; color: var(--text-dimmer); }
|
|
51
|
+
@keyframes login-browser-spin { to { transform: rotate(360deg); } }
|
|
52
|
+
@media (max-width: 600px) {
|
|
53
|
+
.login-browser { width: 100vw; height: 100dvh; margin: 0; border: 0; border-radius: 0; }
|
|
54
|
+
.login-browser-header { padding: max(12px, env(safe-area-inset-top)) 12px 12px; gap: 9px; }
|
|
55
|
+
.login-browser-vendor { width: 30px; height: 30px; border-radius: 8px; }
|
|
56
|
+
.login-browser h2 { font-size: 14px; }
|
|
57
|
+
.login-browser .login-browser-keyboard-button { display: flex; }
|
|
58
|
+
.login-browser-footer { flex-direction: column; align-items: stretch; gap: 10px; padding: 10px 12px max(12px, env(safe-area-inset-bottom)); }
|
|
59
|
+
.login-browser-status { justify-content: center; }
|
|
60
|
+
.login-browser-privacy { text-align: center; }
|
|
61
|
+
.login-browser .login-browser-terminal { min-height: 40px; font-size: 12px; }
|
|
62
|
+
}
|
|
63
|
+
@media (prefers-reduced-motion: reduce) { .login-browser-spinner { animation: none; } }
|
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
|
|
@@ -92,6 +93,7 @@ import { handleSkillInstallWs } from './app-skills-install.js';
|
|
|
92
93
|
import { handleNotificationsState, handleNotificationCreated, handleNotificationDismissed, handleNotificationDismissedAll, showUpdateBanner } from './app-notifications.js';
|
|
93
94
|
import { handleUpdateSnoozed } from './update-snooze.js';
|
|
94
95
|
import { autoStartLoginIfNeeded, handleVendorLoginReady, handleVendorLoginState, handleVendorLoginError, handleAuthRefreshed } from './vendor-login.js';
|
|
96
|
+
import { handleLoginBrowserMessage } from './vendor-login-browser.js';
|
|
95
97
|
import { handleDebatePreparing, handleDebateBriefReady, renderDebateBriefReady, handleDebateStarted, renderDebateStarted, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, renderDebateCommentInjected, handleDebateResumed, handleDebateEnded, renderDebateEnded, handleDebateError, isDebateActive, renderMcpDebateProposal, renderDebateUserResume } from './debate.js';
|
|
96
98
|
import { handleMentionStart, handleMentionActivity, handleMentionStream, handleMentionDone, handleMentionError, renderMentionUser, renderMentionResponse, renderUserMention } from './mention.js';
|
|
97
99
|
|
|
@@ -103,6 +105,11 @@ var connectOverlay = document.getElementById("connect-overlay");
|
|
|
103
105
|
initMessageDeliveryUi();
|
|
104
106
|
|
|
105
107
|
export function processMessage(msg) {
|
|
108
|
+
if (handleSharedBrowserMessage(msg)) return;
|
|
109
|
+
if (msg.type === "vendor_login_browser_frame" || msg.type === "vendor_login_browser_status") {
|
|
110
|
+
handleLoginBrowserMessage(msg);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
106
113
|
if (handleIssuesMessage(msg)) return;
|
|
107
114
|
if (handleAutonomousRunMessage(msg)) return;
|
|
108
115
|
if (handleLoopInterviewMessage(msg)) return;
|
|
@@ -170,7 +170,7 @@ function showBanner(notif, autoDismissMs) {
|
|
|
170
170
|
} else if (isAuthRequired) {
|
|
171
171
|
actionsHtml =
|
|
172
172
|
'<div class="notif-banner-actions">' +
|
|
173
|
-
'<button class="notif-banner-auth-login notif-banner-update-now">
|
|
173
|
+
'<button class="notif-banner-auth-login notif-banner-update-now">Sign in</button>' +
|
|
174
174
|
'</div>';
|
|
175
175
|
} else if (isTuiAttention) {
|
|
176
176
|
actionsHtml =
|
|
@@ -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
|
}));
|