webcake-landing-mcp 1.0.12 → 1.0.13
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/dist/auth/login.js +83 -4
- package/package.json +1 -1
package/dist/auth/login.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { createServer } from "node:http";
|
|
20
20
|
import { randomBytes } from "node:crypto";
|
|
21
|
-
import { spawn } from "node:child_process";
|
|
21
|
+
import { spawn, execFile } from "node:child_process";
|
|
22
22
|
import { saveSavedConfig, resolveEnv, ENVIRONMENTS } from "../persistence/config.js";
|
|
23
23
|
function parseArgs(argv) {
|
|
24
24
|
const get = (name) => {
|
|
@@ -44,9 +44,83 @@ function openBrowser(url) {
|
|
|
44
44
|
/* ignore — the URL is also printed */
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
// Chrome won't let a page close a tab it didn't open (window.close() is blocked),
|
|
48
|
+
// so instead we bring the user's terminal back to the foreground from Node. We
|
|
49
|
+
// snapshot whatever app is frontmost just before opening the browser (that's the
|
|
50
|
+
// terminal that ran the command) and re-activate it once the token arrives.
|
|
51
|
+
// macOS only (AppleScript); a no-op elsewhere — the success page still shows.
|
|
52
|
+
function captureFrontmostApp() {
|
|
53
|
+
if (process.platform !== "darwin")
|
|
54
|
+
return Promise.resolve(undefined);
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
let done = false;
|
|
57
|
+
const finish = (v) => {
|
|
58
|
+
if (done)
|
|
59
|
+
return;
|
|
60
|
+
done = true;
|
|
61
|
+
resolve(v);
|
|
62
|
+
};
|
|
63
|
+
const child = execFile("osascript", ["-e", 'tell application "System Events" to get name of first application process whose frontmost is true'], (err, stdout) => finish(err ? undefined : stdout.trim() || undefined));
|
|
64
|
+
// Never let login stall: the first run may hang on the macOS Automation
|
|
65
|
+
// permission prompt. Give up after 2s (re-focus is just a nicety).
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
try {
|
|
68
|
+
child.kill();
|
|
69
|
+
}
|
|
70
|
+
catch { /* noop */ }
|
|
71
|
+
finish(undefined);
|
|
72
|
+
}, 2000).unref();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function activateApp(name) {
|
|
76
|
+
if (!name || process.platform !== "darwin")
|
|
77
|
+
return;
|
|
78
|
+
// Re-focus by process name via System Events (works for terminals whose app
|
|
79
|
+
// name differs from the process, e.g. iTerm/Terminal/Warp/VS Code).
|
|
80
|
+
execFile("osascript", ["-e", `tell application "System Events" to set frontmost of (first application process whose name is "${name.replace(/"/g, '\\"')}") to true`], () => { });
|
|
81
|
+
}
|
|
82
|
+
const SUCCESS_HTML = `<!doctype html><html lang="en"><head><meta charset="utf-8">
|
|
83
|
+
<meta name="viewport" content="width=device-width,initial-scale=1"><title>Connected to Webcake</title>
|
|
84
|
+
<style>
|
|
85
|
+
:root{color-scheme:light dark}
|
|
86
|
+
*{box-sizing:border-box}
|
|
87
|
+
body{margin:0;min-height:100vh;display:flex;align-items:center;justify-content:center;
|
|
88
|
+
font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
|
|
89
|
+
background:linear-gradient(135deg,#eef2ff 0%,#faf5ff 100%);color:#1e293b}
|
|
90
|
+
@media(prefers-color-scheme:dark){body{background:linear-gradient(135deg,#0f172a 0%,#1e1b4b 100%);color:#e2e8f0}}
|
|
91
|
+
.card{background:#fff;border-radius:20px;padding:48px 40px;max-width:420px;width:calc(100% - 32px);
|
|
92
|
+
text-align:center;box-shadow:0 20px 60px rgba(79,70,229,.18);animation:rise .5s cubic-bezier(.2,.8,.2,1)}
|
|
93
|
+
@media(prefers-color-scheme:dark){.card{background:#1e293b;box-shadow:0 20px 60px rgba(0,0,0,.5)}}
|
|
94
|
+
@keyframes rise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
|
|
95
|
+
.badge{width:84px;height:84px;margin:0 auto 24px;border-radius:50%;display:flex;align-items:center;justify-content:center;
|
|
96
|
+
background:linear-gradient(135deg,#22c55e,#16a34a);box-shadow:0 8px 24px rgba(34,197,94,.4);animation:pop .45s .15s both cubic-bezier(.2,1.4,.4,1)}
|
|
97
|
+
@keyframes pop{from{transform:scale(0)}to{transform:scale(1)}}
|
|
98
|
+
.badge svg{width:44px;height:44px;stroke:#fff;stroke-width:3.5;fill:none;stroke-linecap:round;stroke-linejoin:round}
|
|
99
|
+
.badge path{stroke-dasharray:32;stroke-dashoffset:32;animation:draw .4s .4s forwards ease-out}
|
|
100
|
+
@keyframes draw{to{stroke-dashoffset:0}}
|
|
101
|
+
h1{margin:0 0 10px;font-size:1.55rem;font-weight:700}
|
|
102
|
+
p{margin:0;font-size:1rem;line-height:1.6;color:#64748b}
|
|
103
|
+
@media(prefers-color-scheme:dark){p{color:#94a3b8}}
|
|
104
|
+
.hint{margin-top:24px;display:inline-flex;align-items:center;gap:8px;padding:10px 16px;border-radius:10px;
|
|
105
|
+
background:#f1f5f9;font-size:.9rem;color:#475569}
|
|
106
|
+
@media(prefers-color-scheme:dark){.hint{background:#0f172a;color:#94a3b8}}
|
|
107
|
+
.hint code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:600;color:#4f46e5}
|
|
108
|
+
@media(prefers-color-scheme:dark){.hint code{color:#a5b4fc}}
|
|
109
|
+
</style></head>
|
|
110
|
+
<body>
|
|
111
|
+
<main class="card">
|
|
112
|
+
<div class="badge"><svg viewBox="0 0 24 24"><path d="M5 13l4 4L19 7"/></svg></div>
|
|
113
|
+
<h1>Connected to Webcake</h1>
|
|
114
|
+
<p>Your account is linked. You can close this tab now.</p>
|
|
115
|
+
<div class="hint">👉 Return to your <code>terminal</code> to continue</div>
|
|
116
|
+
</main>
|
|
117
|
+
<script>
|
|
118
|
+
// The terminal is re-focused from the CLI side. Still try window.close() for
|
|
119
|
+
// browsers that allow it (no-op in Chrome for tabs it didn't open) — no alert,
|
|
120
|
+
// which would only steal focus back from the terminal.
|
|
121
|
+
setTimeout(function(){ try { window.close(); } catch (e) {} }, 800);
|
|
122
|
+
</script>
|
|
123
|
+
</body></html>`;
|
|
50
124
|
function resolveConnectUrl(opts, appBase) {
|
|
51
125
|
if (opts.connectUrl)
|
|
52
126
|
return opts.connectUrl; // explicit --connect-url override
|
|
@@ -62,6 +136,9 @@ export async function runLogin(argv) {
|
|
|
62
136
|
const appBase = process.env.WEBCAKE_APP_BASE || preset.appBase;
|
|
63
137
|
const connectUrl = resolveConnectUrl(opts, appBase);
|
|
64
138
|
const state = randomBytes(16).toString("hex");
|
|
139
|
+
// Remember the terminal that's frontmost now, so we can re-focus it once the
|
|
140
|
+
// browser hands the token back (Chrome can't auto-close its own tab).
|
|
141
|
+
const terminalApp = await captureFrontmostApp();
|
|
65
142
|
await new Promise((resolve, reject) => {
|
|
66
143
|
const server = createServer((req, res) => {
|
|
67
144
|
const url = new URL(req.url || "/", "http://127.0.0.1");
|
|
@@ -83,6 +160,8 @@ export async function runLogin(argv) {
|
|
|
83
160
|
});
|
|
84
161
|
res.writeHead(200, { "content-type": "text/html" }).end(SUCCESS_HTML);
|
|
85
162
|
console.error(`\n✓ Connected. Token saved to ${path} (api ${apiBase}).`);
|
|
163
|
+
// Pull the terminal back to the front (best-effort; no-op off macOS).
|
|
164
|
+
activateApp(terminalApp);
|
|
86
165
|
server.close();
|
|
87
166
|
resolve();
|
|
88
167
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcake-landing-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "MCP server exposing Webcake landing-page element schemas + AI usage hints, and persisting LLM-generated page sources to a Webcake backend.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|