@lifeaitools/clauth 1.5.6 β 1.5.8
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/cli/commands/serve.js +56 -8
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -739,6 +739,7 @@ function dashboardHtml(port, whitelist, isStaged = false) {
|
|
|
739
739
|
<button class="btn-add" onclick="toggleAddService()">+ Add Service</button>
|
|
740
740
|
<button class="btn-check" id="check-btn" onclick="checkAll()">⬀ Check All</button>
|
|
741
741
|
<button class="btn-lock" onclick="lockVault()">π Lock</button>
|
|
742
|
+
<button class="btn-stop" onclick="restartDaemon()" style="background:#1a2e1a;border:1px solid #166534;color:#86efac" title="Restart daemon β keeps vault unlocked">βΊ Restart</button>
|
|
742
743
|
<button class="btn-stop" onclick="stopDaemon()" style="background:#7f1d1d;border:1px solid #991b1b;color:#fca5a5" title="Stop daemon β password required on next start">βΉ Stop</button>
|
|
743
744
|
<button class="btn-cancel" style="margin-left:auto" onclick="toggleChangePw()">Change Password</button>
|
|
744
745
|
</div>
|
|
@@ -1131,6 +1132,17 @@ async function makeLive() {
|
|
|
1131
1132
|
}
|
|
1132
1133
|
}
|
|
1133
1134
|
|
|
1135
|
+
// ββ Restart daemon (keeps boot.key β vault stays unlocked) ββ
|
|
1136
|
+
async function restartDaemon() {
|
|
1137
|
+
if (!confirm("Restart the daemon?\\n\\nThe vault will stay unlocked (boot.key kept).")) return;
|
|
1138
|
+
const btn = document.querySelector('[onclick="restartDaemon()"]');
|
|
1139
|
+
if (btn) { btn.disabled = true; btn.textContent = "βΊ Restartingβ¦"; }
|
|
1140
|
+
try {
|
|
1141
|
+
await fetch(BASE + "/restart", { method: "POST" });
|
|
1142
|
+
} catch {}
|
|
1143
|
+
document.getElementById("main-view").innerHTML = '<div style="text-align:center;padding:80px 20px"><div style="font-size:3rem;margin-bottom:16px">βΊ</div><div style="font-size:1.1rem;color:#86efac">Restartingβ¦</div><div style="font-size:.85rem;color:#64748b;margin-top:8px">Page will reload automatically.</div></div>';
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1134
1146
|
// ββ Stop daemon (user-initiated β clears boot.key, requires password on restart) ββ
|
|
1135
1147
|
async function stopDaemon() {
|
|
1136
1148
|
if (!confirm("Stop the daemon?\\n\\nCredentials will need to be re-entered on next start.")) return;
|
|
@@ -2988,9 +3000,23 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
2988
3000
|
return res.end(JSON.stringify({ access_token: accessToken, token_type: "Bearer", expires_in: 86400 }));
|
|
2989
3001
|
}
|
|
2990
3002
|
|
|
3003
|
+
// ββ MCP path helpers ββ
|
|
3004
|
+
const MCP_PATHS = ["/mcp", "/gws", "/clauth"];
|
|
3005
|
+
const isMcpPath = MCP_PATHS.includes(reqPath);
|
|
3006
|
+
function toolsForPath(p) {
|
|
3007
|
+
if (p === "/gws") return MCP_TOOLS.filter(t => t.name.startsWith("gws_"));
|
|
3008
|
+
if (p === "/clauth") return MCP_TOOLS.filter(t => t.name.startsWith("clauth_"));
|
|
3009
|
+
return MCP_TOOLS; // /mcp β all tools
|
|
3010
|
+
}
|
|
3011
|
+
function serverNameForPath(p) {
|
|
3012
|
+
if (p === "/gws") return "gws";
|
|
3013
|
+
if (p === "/clauth") return "clauth";
|
|
3014
|
+
return "clauth";
|
|
3015
|
+
}
|
|
3016
|
+
|
|
2991
3017
|
// ββ MCP OAuth-protected endpoint (for claude.ai web) ββ
|
|
2992
|
-
// POST /mcp β requires Bearer token; returns 401 to trigger OAuth flow
|
|
2993
|
-
if (method === "POST" &&
|
|
3018
|
+
// POST /mcp|/gws|/clauth β requires Bearer token; returns 401 to trigger OAuth flow
|
|
3019
|
+
if (method === "POST" && isMcpPath) {
|
|
2994
3020
|
const authHeader = req.headers.authorization;
|
|
2995
3021
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
2996
3022
|
const base = oauthBase();
|
|
@@ -3012,8 +3038,8 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3012
3038
|
}
|
|
3013
3039
|
|
|
3014
3040
|
// ββ MCP Streamable HTTP transport (2025-03-26 spec) ββ
|
|
3015
|
-
// POST /sse
|
|
3016
|
-
if (method === "POST" && (reqPath === "/sse" ||
|
|
3041
|
+
// POST /sse, /mcp, /gws, /clauth β JSON-RPC over HTTP
|
|
3042
|
+
if (method === "POST" && (reqPath === "/sse" || isMcpPath)) {
|
|
3017
3043
|
let body;
|
|
3018
3044
|
try { body = await readBody(req); } catch {
|
|
3019
3045
|
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
@@ -3022,7 +3048,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3022
3048
|
|
|
3023
3049
|
const id = body.id;
|
|
3024
3050
|
const rpcMethod = body.method;
|
|
3025
|
-
const logMsg = `[${new Date().toISOString()}] Streamable HTTP: ${rpcMethod} id=${id}\n`;
|
|
3051
|
+
const logMsg = `[${new Date().toISOString()}] Streamable HTTP [${reqPath}]: ${rpcMethod} id=${id}\n`;
|
|
3026
3052
|
try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
|
|
3027
3053
|
|
|
3028
3054
|
// Notifications β no response needed
|
|
@@ -3034,7 +3060,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3034
3060
|
if (rpcMethod === "initialize") {
|
|
3035
3061
|
const result = {
|
|
3036
3062
|
protocolVersion: "2025-03-26",
|
|
3037
|
-
serverInfo: { name:
|
|
3063
|
+
serverInfo: { name: serverNameForPath(reqPath), version: VERSION },
|
|
3038
3064
|
capabilities: { tools: {} }
|
|
3039
3065
|
};
|
|
3040
3066
|
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
@@ -3043,7 +3069,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3043
3069
|
|
|
3044
3070
|
if (rpcMethod === "tools/list") {
|
|
3045
3071
|
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
3046
|
-
return res.end(JSON.stringify({ jsonrpc: "2.0", id, result: { tools:
|
|
3072
|
+
return res.end(JSON.stringify({ jsonrpc: "2.0", id, result: { tools: toolsForPath(reqPath) } }));
|
|
3047
3073
|
}
|
|
3048
3074
|
|
|
3049
3075
|
if (rpcMethod === "tools/call") {
|
|
@@ -3272,6 +3298,28 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3272
3298
|
return ok(res, { status: tunnelStatus });
|
|
3273
3299
|
}
|
|
3274
3300
|
|
|
3301
|
+
// POST /restart β spawn fresh process then exit (keeps boot.key, vault stays unlocked)
|
|
3302
|
+
if (method === "POST" && reqPath === "/restart") {
|
|
3303
|
+
ok(res, { ok: true, message: "restarting" });
|
|
3304
|
+
const { spawn } = await import("child_process");
|
|
3305
|
+
const cliEntry = path.resolve(__dirname, "../index.js");
|
|
3306
|
+
const childArgs = [cliEntry, "serve", "start", "--port", String(port)];
|
|
3307
|
+
if (password) childArgs.push("--pw", password);
|
|
3308
|
+
if (whitelist) childArgs.push("--services", whitelist.join(","));
|
|
3309
|
+
if (tunnelHostname) childArgs.push("--tunnel", tunnelHostname);
|
|
3310
|
+
const out = fs.openSync(LOG_FILE, "a");
|
|
3311
|
+
const child = spawn(process.execPath, childArgs, {
|
|
3312
|
+
detached: true,
|
|
3313
|
+
stdio: ["ignore", out, out],
|
|
3314
|
+
env: { ...process.env, __CLAUTH_DAEMON: "1" },
|
|
3315
|
+
});
|
|
3316
|
+
child.unref();
|
|
3317
|
+
stopTunnel();
|
|
3318
|
+
removePid();
|
|
3319
|
+
setTimeout(() => process.exit(0), 300);
|
|
3320
|
+
return;
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3275
3323
|
// GET|POST /shutdown (for daemon stop β programmatic, keeps boot.key)
|
|
3276
3324
|
// Accept POST as well β older scripts and curl default to POST
|
|
3277
3325
|
if ((method === "GET" || method === "POST") && reqPath === "/shutdown") {
|
|
@@ -4287,7 +4335,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
4287
4335
|
// Don't count browser noise, MCP discovery probes, or OAuth probes as auth failures
|
|
4288
4336
|
const isBenign = reqPath.startsWith("/.well-known/") || [
|
|
4289
4337
|
"/favicon.ico", "/robots.txt", "/apple-touch-icon.png", "/apple-touch-icon-precomposed.png",
|
|
4290
|
-
"/sse", "/mcp", "/message", "/register", "/authorize", "/token", "/shutdown",
|
|
4338
|
+
"/sse", "/mcp", "/gws", "/clauth", "/message", "/register", "/authorize", "/token", "/shutdown", "/restart",
|
|
4291
4339
|
].includes(reqPath);
|
|
4292
4340
|
if (isBenign) {
|
|
4293
4341
|
res.writeHead(404, { "Content-Type": "application/json", ...CORS });
|